__proto__ VS. nguyên mẫu trong JavaScript


785

Con số này một lần nữa cho thấy mọi đối tượng đều có nguyên mẫu. Hàm xây dựng Foo cũng có hàm riêng __proto__là Function.prototype và lần lượt cũng tham chiếu qua thuộc tính của nó __proto__một lần nữa đến Object.prototype. Do đó, lặp lại, Foo.prototype chỉ là một thuộc tính rõ ràng của Foo dùng để chỉ nguyên mẫu của các đối tượng b và c.

var b = new Foo(20);
var c = new Foo(30);

Sự khác biệt giữa __proto__và là prototypegì?

nhập mô tả hình ảnh ở đây

Con số được lấy từ dmitrysoshnikov.com .



5
Tôi nghĩ từ trên xuống hoặc từ dưới lên là vấn đề ưu tiên. Tôi thực sự thích nó theo cách này, vì vậy tôi có thể theo dõi sơ đồ cho đến khi tôi tìm thấy một cái gì đó đến từ đâu.
Mike Lippert

1
Tôi thích cách JavaScript sử dụng kế thừa nguyên mẫu để phân giải y.constructor thành y .__ proto __. Constructor. Tôi cũng thích cách Object.prototype nằm ở đầu chuỗi kế thừa nguyên mẫu với Object.prototype .__ proto__ được đặt thành null. Tôi cũng thích cách sơ đồ tạo ra một hình ảnh khái niệm ba cột về cách lập trình viên nghĩ về các đối tượng là 1. thể hiện, 2. hàm tạo, 3. nguyên mẫu mà các hàm tạo liên kết với các thể hiện đó khi được khởi tạo thông qua từ khóa mới.
John Sonderson

Sơ đồ có ý nghĩa ngay lập tức sau khi bạn xem một cái gì đó như youtube.com/watch?v=_JJgSbuj5VI , btw
mlvljr

Và bây giờ, khi tôi đọc qua các câu trả lời, cảm thấy bắt buộc phải thực sự đề xuất video trên, vì nó thực sự có một lời giải thích rõ ràng (và không phải WTFy) về những gì đang diễn ra :)
mlvljr

Câu trả lời:


766

__proto__là đối tượng thực tế được sử dụng trong chuỗi tra cứu để giải quyết các phương thức, v.v. prototypelà đối tượng được sử dụng để xây dựng __proto__khi bạn tạo một đối tượng với new:

( new Foo ).__proto__ === Foo.prototype;
( new Foo ).prototype === undefined;

239
Ah! Vì vậy, prototypekhông có sẵn trên các cá thể (hoặc các đối tượng khác), mà chỉ có trên các hàm xây dựng.
rvighne

43
@rvighne: prototypechỉ có sẵn trên các chức năng kể từ khi họ có nguồn gốc từ Function, FunctionObjectnhưng trong bất cứ điều gì khác nó không phải là. Tuy nhiên, __proto__có sẵn ở khắp mọi nơi.
Tarik

19
Vì vậy, __proto__đối tượng thực tế được lưu và sử dụng làm nguyên mẫu trong khi Myconstructure.prototypechỉ là một bản thiết kế, trong __proto__đó, thực sự là đối tượng thực sự được lưu và được sử dụng làm protoype. Do đó myobject.prototypesẽ không phải là một thuộc tính của đối tượng thực tế bởi vì nó chỉ là một thứ tạm thời được sử dụng bởi hàm tạo để phác thảo những gì myobject.__proto__sẽ trông như thế nào.
Alex_Nabu

9
Có công bằng không khi nói rằng thuộc __proto__tính của một đối tượng là một con trỏ tới thuộc tính của hàm tạo của đối tượng prototype? tức là foo .__ proto__ === foo.constructor.prototype
Niko Bellic

10
@Alex_Nabu Không hoàn toàn. newCar.__proto__ IS Car.prototype , không phải là một ví dụ Car.prototype. Trong khi Car.protoype IS là một ví dụ của một object. Car.prototypekhông phải là thứ mang lại newCarbất kỳ tính chất hay cấu trúc nào, nó chỉ đơn giản thứ tiếp theo objecttrong newCarchuỗi nguyên mẫu. Car.prototypekhông phải là một tạm thời object. Đó là objectgiá trị được đặt làm giá trị của thuộc __proto__tính của bất kỳ objects mới nào được sử dụng Carnhư a constructor. Nếu bạn muốn nghĩ về bất cứ điều gì như một bản thiết kế object, hãy nghĩ về Carmột bản thiết kế cho những chiếc xe mới object.
seangwright

336

prototypelà một thuộc tính của một đối tượng Hàm. Nó là nguyên mẫu của các đối tượng được xây dựng bởi chức năng đó.

__proto__là tài sản nội bộ của một đối tượng, trỏ đến nguyên mẫu của nó. Các tiêu chuẩn hiện tại cung cấp một Object.getPrototypeOf(O)phương pháp tương đương , mặc dù tiêu chuẩn thực tế __proto__nhanh hơn.

Bạn có thể tìm thấy các instanceofmối quan hệ bằng cách so sánh một hàm prototypevới __proto__chuỗi của đối tượng và bạn có thể phá vỡ các mối quan hệ này bằng cách thay đổi prototype.

function Point(x, y) {
    this.x = x;
    this.y = y;
}

var myPoint = new Point();

// the following are all true
myPoint.__proto__ == Point.prototype
myPoint.__proto__.__proto__ == Object.prototype
myPoint instanceof Point;
myPoint instanceof Object;

Đây Pointlà một hàm xây dựng, nó xây dựng một đối tượng (cấu trúc dữ liệu) theo thủ tục. myPointlà một đối tượng được xây dựng bởi Point()vì vậy Point.prototypeđược lưu myPoint.__proto__vào thời điểm đó.


2
Ngoài ra nếu bạn thay đổi thuộc __proto__tính của một đối tượng, nó sẽ thay đổi đối tượng mà việc tra cứu nguyên mẫu được thực hiện. Chẳng hạn, bạn có thể thêm một đối tượng của các phương thức dưới dạng một hàm __proto__để có một loại đối tượng thể hiện có thể gọi được.
kzh

myPoint .__ proto __. constructor.prototype == Point.prototype
Francisco

@kzh lol đã cho tôi kết quả hài hước console.log(obj1.call) // [Function: call] obj1.call()// TypeError: obj1.call không phải là một chức năng. Tôi đã làmobj.__proto__ = Function.__proto__
abhisekp

myFn.__proto__ = {foo: 'bar'}
kzh

Tôi nghĩ rằng tôi đã có điểm của bạn.
Truyện tranh

120

Thuộc tính nguyên mẫu được tạo khi một hàm được khai báo.

Ví dụ:

 function Person(dob){
    this.dob = dob
 }; 

Person.prototypethuộc tính được tạo trong nội bộ khi bạn khai báo hàm trên. Nhiều thuộc tính có thể được thêm vào Person.prototype được chia sẻ bởi các cá thể Person được tạo bằng Person () mới.

// adds a new method age to the Person.prototype Object.
Person.prototype.age = function(){return date-dob}; 

Điều đáng chú ý Person.prototypeObjecttheo nghĩa đen theo mặc định (nó có thể được thay đổi theo yêu cầu).

Mỗi phiên bản được tạo bằng cách sử dụng new Person()có một thuộc __proto__tính trỏ đến Person.prototype. Đây là chuỗi được sử dụng để đi qua để tìm một thuộc tính của một đối tượng cụ thể.

var person1 = new Person(somedate);
var person2 = new Person(somedate);

tạo 2 thể hiện của Person, 2 đối tượng này có thể gọi agephương thức Person.prototypeperson1.age, person2.age.

Trong hình trên từ câu hỏi của bạn, bạn có thể thấy đó Foolà một Function Objectvà do đó nó có một __proto__liên kết đến Function.prototypelần lượt là một thể hiện Objectvà có một __proto__liên kết đến Object.prototype. Liên kết proto kết thúc ở đây với __proto__trong Object.prototypechỉ đến null.

Bất kỳ đối tượng nào cũng có thể có quyền truy cập vào tất cả các thuộc tính trong chuỗi proto của nó như được liên kết bởi __proto__, do đó tạo thành cơ sở cho sự kế thừa nguyên mẫu.

__proto__không phải là một cách tiêu chuẩn để truy cập chuỗi nguyên mẫu, cách tiếp cận tiêu chuẩn nhưng tương tự là sử dụng Object.getPrototypeOf(obj).

Mã dưới đây cho instanceoftoán tử cho hiểu rõ hơn:

instanceofToán tử lớp đối tượng trả về truekhi một đối tượng là một thể hiện của Class, cụ thể hơn nếu Class.prototypeđược tìm thấy trong chuỗi proto của đối tượng đó thì đối tượng là một thể hiện của Class đó.

function instanceOf(Func){
  var obj = this;
  while(obj !== null){
    if(Object.getPrototypeOf(obj) === Func.prototype)
      return true;
    obj = Object.getPrototypeOf(obj);
  }
  return false;
}      

Phương thức trên có thể được gọi là: instanceOf.call(object, Class)trả về true nếu đối tượng là thể hiện của Class.


2
Tôi đã tự hỏi tại sao prototypeđối tượng được tạo ra trong nội bộ ngay từ đầu? Có thể chỉ cần gán các phương thức tĩnh cho chính đối tượng hàm. ví dụ function f(a){this.a = a}; f.increment = function(){return ++this.a}? Tại sao cách này không được chọn qua việc thêm các phương thức vào prototypeđối tượng? Điều này sẽ hoạt động nếu f.__proto__ = gg là lớp cơ sở.
abhisekp

Có thể prototypeđối tượng được chọn để chia sẻ vì chỉ các thuộc tính hàm tạo độc quyền có thể được lưu trữ trong đối tượng hàm xây dựng hàm.
abhisekp

1
Trên thực tế, đó sẽ là một mớ hỗn độn vì instanceofsẽ dẫn đến kết quả ({}) instanceof Function === truelà sẽ không có cách nào để phân biệt giữa các nguyên mẫu nếu prototypetài sản bị xóa.
abhisekp

@abhisekp Ý của bạn là gì: "Điều này sẽ hoạt động nếu f .__ proto__ = g trong đó g là lớp cơ sở." Tôi không biết điều này có nghĩa gì mà tôi không hiểu, nhưng nếu bạn thêm các thuộc tính và phương thức theo cách đó, thì khi bạn sử dụng newtừ khóa để tạo một thể hiện, các thuộc tính và phương thức sẽ không được sao chép kết thúc.
doubleOrt

67

Một cách hay để nghĩ về nó là ...

prototypeđược sử dụng bởi các constructor()chức năng. Nó thực sự đã được gọi là một cái gì đó như "prototypeToInstall", vì đó là những gì nó được.

__proto__là "nguyên mẫu được cài đặt" trên một đối tượng (được tạo / cài đặt trên đối tượng từ constructor()chức năng đã nói )


2
Tôi đã nâng cấp nó, nhưng có lẽ lý do downvote là vì câu lệnh "nguyên mẫu được sử dụng bởi các hàm constructor ()" nghe có vẻ như không có chức năng của hàm tạo, tuy nhiên không phải là trường hợp của chúng ta bây giờ cũng không phải là trọng tâm của chúng ta người ta có thể lưu ý rằng mọi chức năng đều có khả năng là một nhà xây dựng nếu được gọi mới ...
yoel halb 2/215

2
Vui lòng thay đổi " constructor()hàm" thành "hàm xây dựng", vì có thể có sự nhầm lẫn với " __proto__.constructor()hàm". Tôi coi điều này quan trọng, vì __proto __. Constructor không thực sự được gọi khi newsử dụng từ khóa.
Alexander Gonchiy

1
Câu lệnh " nguyên mẫu được sử dụng bởi các hàm constructor () " chỉ nói lên một phần của một sự kiện quan trọng nhưng đã nói với nó theo cách có khả năng khiến người đọc nghĩ rằng đó là toàn bộ sự thật. nguyên mẫu được tạo bên trong cho mỗi lần khai báo hàm trong Javascript, bất kể hàm đó sẽ được gọi như thế nào trong tương lai - có hoặc không có từ khóa mới ; nguyên mẫu của một hàm khai báo trỏ đến một đối tượng theo nghĩa đen.
Yiling

62

Để giải thích chúng ta hãy tạo một hàm

 function a (name) {
  this.name = name;
 }

Khi JavaScript thực thi mã này, nó thêm thuộc prototypetính vào a, thuộc prototypetính là một đối tượng có hai thuộc tính cho nó:

  1. constructor
  2. __proto__

Vì vậy, khi chúng tôi làm

a.prototype nó trở lại

     constructor: a  // function definition
    __proto__: Object

Bây giờ bạn có thể thấy constructorkhông có gì ngoài achính chức năng và __proto__trỏ đến cấp độ gốc Objectcủa JavaScript.

Chúng ta hãy xem những gì xảy ra khi chúng ta sử dụng achức năng với newtừ khóa.

var b = new a ('JavaScript');

Khi JavaScript thực thi mã này, nó thực hiện 4 điều:

  1. Nó tạo ra một đối tượng mới, một đối tượng trống // {}
  2. Nó tạo ra __proto__trên bvà làm cho nó trỏ đến a.prototypevậyb.__proto__ === a.prototype
  3. Nó thực thi a.prototype.constructor(là định nghĩa của hàm a) với đối tượng mới được tạo (được tạo ở bước 1) làm bối cảnh của nó (do đó), do đó thuộc nametính được truyền dưới dạng 'JavaScript' (được thêm vào this) được thêm vào đối tượng mới được tạo.
  4. Nó trả về đối tượng mới được tạo trong (được tạo ở bước # 1) để var bđược gán cho đối tượng mới được tạo.

Bây giờ nếu chúng ta thêm a.prototype.car = "BMW"và làm b.car , đầu ra "BMW" sẽ xuất hiện.

điều này là do khi JavaScript thực thi mã này, nó đã tìm kiếm thuộc cartính b, nó không tìm thấy JavaScript được sử dụng b.__proto__(được tạo để trỏ đến 'a.prototype' trong bước # 2) và tìm thấy thuộc cartính để trả về "BMW".


2
1. constructorkhông trở về a()! Nó trở lại a. 2. __proto__trả về Object.prototype, không phải là đối tượng gốc trong Javascript.
doubleOrt

1
Đây là một câu trả lời tuyệt vời!
john-raymon

+1 đây là câu trả lời tốt nhất để giải thích nguyên mẫu nào thực sự là IS (một đối tượng có hai thuộc tính) và cách Javascript thực thi từng đoạn mã. Thông tin này là đáng ngạc nhiên khó đến.
java-nghiện602

53

Nguyên mẫu VS. __proto__ VS. [[Nguyên mẫu]]

Khi tạo một hàm, một đối tượng thuộc tính được gọi là nguyên mẫu sẽ được tạo tự động (bạn không tự tạo) và đang được gắn vào đối tượng hàm (the constructor).
Lưu ý : Nguyên mẫu mới này Đối tượng cũng trỏ đến hoặc có một liên kết riêng-nội bộ đến Đối tượng JavaScript gốc.

Thí dụ:

function Foo () {
    this.name = 'John Doe';
}

// Foo has an object property called prototype.
// prototype was created automatically when we declared the function Foo.
Foo.hasOwnProperty('prototype'); // true

// Now, we can assign properties and methods to it:
Foo.prototype.myName = function () {
    return 'My name is ' + this.name;
}

Nếu bạn tạo một đối tượng mới Foobằng cách sử dụng newtừ khóa, về cơ bản bạn đang tạo (trong số những thứ khác) một đối tượng mới có liên kết nội bộ hoặc riêng tư với Foonguyên mẫu của hàm mà chúng ta đã thảo luận trước đó:

var b = new Foo();

b.[[Prototype]] === Foo.prototype  // true


Các tin liên kết với đối tượng của chức năng đó gọi là dấu ngoặc kép mẫu thử nghiệm hoặc chỉ [[Prototype]]. Nhiều trình duyệt đang cung cấp cho chúng tôi một liên kết công khai với nó được gọi là __proto__!

Cụ thể hơn, __proto__thực sự là một hàm getter thuộc về Đối tượng JavaScript gốc. Nó trả về liên kết nguyên mẫu riêng-nội bộ của bất kỳ thisràng buộc nào (trả về [[Prototype]]của b):

b.__proto__ === Foo.prototype // true

Điều đáng chú ý là bắt đầu từ ECMAScript5 , bạn cũng có thể sử dụng phương thức getPrototypeOf để có được liên kết riêng tư nội bộ:

Object.getPrototypeOf(b) === b.__proto__ // true


Chú ý: câu trả lời này không có ý định để trang trải toàn bộ quá trình của việc tạo ra các đối tượng mới hoặc nhà xây dựng mới, nhưng để giúp hiểu rõ hơn là những gì __proto__, prototype[[Prototype]] và làm thế nào nó hoạt động.


2
@Taurus, nhấp vào tiêu đề, nó dẫn đến tài liệu thông số kỹ thuật ECMAScript. Kiểm tra phần 9 (Hành vi đối tượng thông thường và kỳ lạ) giải thích chi tiết hơn nhiều.
Lior Elrom

Tôi nghĩ có một số sai lầm ở đây: _ một đối tượng mới có liên kết nội bộ hoặc riêng tư với nguyên mẫu của hàm Foo_ Ý bạn là: một đối tượng mới có liên kết nội bộ hoặc riêng tư với nguyên mẫu của Foo ?
Koray Tugay

1
Cảm ơn @KorayTugay! Có, tôi đã viết sai chính tả :) +1
Lior Elrom

31

Để làm cho nó rõ ràng hơn một chút ngoài các câu trả lời tuyệt vời ở trên:

function Person(name){
    this.name = name
 }; 

var eve = new Person("Eve");

eve.__proto__ == Person.prototype //true

eve.prototype  //undefined

Trường hợp__proto__ , các lớpnguyên mẫu .


12

Trong JavaScript, một hàm có thể được sử dụng như một hàm tạo. Điều đó có nghĩa là chúng ta có thể tạo các đối tượng trong số chúng bằng cách sử dụng từ khóa mới. Mỗi hàm xây dựng đi kèm với một đối tượng tích hợp được nối với chúng. Đối tượng tích hợp này được gọi là nguyên mẫu.Instances of a constructor function use __proto__ to access the prototype property of its constructor function.

sơ đồ nguyên mẫu

  1. Đầu tiên chúng ta tạo một constructor : function Foo(){}. Để rõ ràng, Foo chỉ là một chức năng khác. Nhưng chúng ta có thể tạo một đối tượng từ nó với từ khóa mới. Đó là lý do tại sao chúng ta gọi nó là hàm xây dựng

  2. Mỗi chức năng có một thuộc tính duy nhất được gọi là thuộc tính nguyên mẫu. Vì vậy, hàm Con constructor Foocó một thuộc tính nguyên mẫu trỏ đến nguyên mẫu của nó, đó là Foo.prototype(xem hình ảnh).

  3. Các hàm xây dựng chính là một hàm là một thể hiện của một hàm tạo hệ thống được gọi là hàm tạo [[Function]]. Vì vậy, chúng ta có thể nói rằng nó function Foođược xây dựng bởi một hàm tạo [[Function]]. Vì vậy, ý chí __proto__của chúng tôi Foo functionchỉ ra nguyên mẫu của nhà xây dựng của nó, đó là Function.prototype.

  4. Function.prototypebản thân nó không là gì ngoài một đối tượng được xây dựng từ một nhà xây dựng hệ thống khác được gọi là [[Object]]. Vì vậy, [[Object]]là các nhà xây dựng của Function.prototype. Vì vậy, chúng ta có thể nói Function.prototypelà một ví dụ của [[Object]]. Vì vậy, __proto__các Function.prototypeđiểm đến Object.prototype.

  5. Object.prototypelà người đàn ông cuối cùng đứng trong chuỗi nguyên mẫu. Tôi có nghĩa là nó đã không được xây dựng. Nó đã có sẵn trong hệ thống. Vì vậy, __proto__điểm của nó để null.

  6. Bây giờ chúng ta đến với các trường hợp Foo. Khi chúng ta tạo một cá thể bằng cách sử dụng new Foo(), nó tạo ra một đối tượng mới là một thể hiện của Foo. Điều đó có nghĩa Foolà người xây dựng các trường hợp này. Ở đây chúng tôi tạo ra hai trường hợp (x và y). __proto__của x và y do đó trỏ đến Foo.prototype.


Chỉ cần rõ ràng: các trường hợp không có thuộc tính .prototype? Chỉ có chức năng xây dựng phải không? ... Vì vậy, một sự khác biệt giữa một cá thể và hàm xây dựng của nó là: các hàm xây dựng có cả 1. proto 2. đối tượng .prototype trong khi các thể hiện chỉ có thuộc tính .__ proto__ ... đúng không?
Shaz

@Shaz bạn nói đúng. các thể hiện sử dụng proto của chúng để truy cập thuộc tính nguyên mẫu của hàm constructor của chúng.
AL-zami

Nhưng tại sao nó lại như vậy khi bạn viết: var car = Object.create (Xe); bạn sẽ nhận được xe .__ proto__ = Xe NHƯNG bạn cũng có được một thuộc tính car.prototype trỏ đến Xe.prototype?
Shaz

@shaz bạn có thể cung cấp một jsfiddle để tôi có thể hình dung tình hình không?
AL-zami

1
ở đây car.prototype là một tài sản được thừa kế. xe thừa hưởng tài sản 'nguyên mẫu' từ chức năng xe. nên car.prototype === xe.prototype. Tài sản "nguyên mẫu" là một tài sản trên xe. xe có thể truy cập nó thông qua chuỗi nguyên mẫu của nó. Tôi hy vọng điều này sẽ xóa
tan

8

Tóm lược:

Các __proto__tài sản của một đối tượng là một tài sản mà các bản đồ vào prototypecủa hàm constructor của đối tượng. Nói cách khác:

instance.__proto__ === constructor.prototype // true

Điều này được sử dụng để tạo thành prototypechuỗi của một đối tượng. Các prototypechuỗi là một cơ chế tra cứu cho các thuộc tính trên một đối tượng. Nếu thuộc tính của đối tượng được truy cập, trước tiên JavaScript sẽ nhìn vào chính đối tượng đó. Nếu tài sản không được tìm thấy ở đó, nó sẽ leo lên đếnprotochain đến khi tìm thấy (hoặc không)

Thí dụ:

function Person (name, city) {
  this.name = name;
}

Person.prototype.age = 25;

const willem = new Person('Willem');

console.log(willem.__proto__ === Person.prototype); // the __proto__ property on the instance refers to the prototype of the constructor

console.log(willem.age); // 25 doesn't find it at willem object but is present at prototype
console.log(willem.__proto__.age); // now we are directly accessing the prototype of the Person function 

Kết quả nhật ký đầu tiên của chúng tôi true, điều này là do như đã đề cập thuộc __proto__tính của cá thể được tạo bởi hàm tạo đề cập đếnprototype tính của hàm tạo. Hãy nhớ rằng, trong JavaScript, các hàm cũng là Đối tượng. Các đối tượng có thể có các thuộc tính và một thuộc tính mặc định của bất kỳ chức năng nào là một thuộc tính có tên là nguyên mẫu.

Sau đó, khi hàm này được sử dụng làm hàm xây dựng, đối tượng được khởi tạo từ nó sẽ nhận được một thuộc tính được gọi __proto__. Và thuộc __proto__tính này đề cập đến thuộc prototypetính của hàm xây dựng (theo mặc định mọi hàm đều có).

Tại sao điều này hữu ích?

JavaScript có một cơ chế khi tìm kiếm các thuộc tính Objectsđược gọi là 'thừa kế nguyên mẫu' , đây là những gì về cơ bản nó làm:

  • Đầu tiên, nó được kiểm tra nếu thuộc tính nằm trên chính Object. Nếu vậy, tài sản này được trả lại.
  • Nếu thuộc tính không nằm trên chính đối tượng, nó sẽ 'trèo lên protochain'. Về cơ bản nó nhìn vào đối tượng được đề cập bởi __proto__tài sản. Ở đó, nó kiểm tra nếu thuộc tính có sẵn trên đối tượng được gọi bởi __proto__.
  • Nếu thuộc tính không nằm trên __proto__đối tượng, nó sẽ leo lên __proto__chuỗi, đến tận Objectđối tượng.
  • Nếu nó không thể tìm thấy tài sản ở bất cứ đâu trên đối tượng và prototypechuỗi của nó , nó sẽ trở lại undefined.

Ví dụ:

function Person (name) {
  this.name = name;
}

let mySelf = new Person('Willem');

console.log(mySelf.__proto__ === Person.prototype);

console.log(mySelf.__proto__.__proto__ === Object.prototype);


7

Tôi tình cờ học được nguyên mẫu từ You Do not know JS: this & Object Prototypes , đây là một cuốn sách tuyệt vời để hiểu thiết kế bên dưới và làm rõ rất nhiều quan niệm sai lầm (đó là lý do tại sao tôi đang cố gắng tránh sử dụng tính kế thừa và những thứ như thế instanceof).

Nhưng tôi có câu hỏi tương tự như mọi người hỏi ở đây. Một số câu trả lời thực sự hữu ích và khai sáng. Tôi cũng muốn chia sẻ những hiểu biết của tôi.


Nguyên mẫu là gì?

Các đối tượng trong JavaScript có một thuộc tính bên trong, được ký hiệu trong đặc tả là [[Prototype]], nó chỉ đơn giản là một tham chiếu đến một đối tượng khác. Hầu như tất cả các đối tượng được cung cấp một nullgiá trị phi cho tài sản này, tại thời điểm tạo ra chúng.

Làm thế nào để có được nguyên mẫu của một đối tượng?

thông qua __proto__hoặcObject.getPrototypeOf

var a = { name: "wendi" };
a.__proto__ === Object.prototype // true
Object.getPrototypeOf(a) === Object.prototype // true

function Foo() {};
var b = new Foo();
b.__proto__ === Foo.prototype
b.__proto__.__proto__ === Object.prototype

Là gì prototype?

prototypelà một đối tượng được tạo tự động như một thuộc tính đặc biệt của hàm , được sử dụng để thiết lập chuỗi ủy nhiệm (thừa kế), còn gọi là chuỗi nguyên mẫu.

Khi chúng ta tạo một hàm a, prototypesẽ tự động được tạo như một thuộc tính đặc biệt avà lưu mã chức năng trên như constructortrên prototype.

function Foo() {};
Foo.prototype // Object {constructor: function}
Foo.prototype.constructor === Foo // true

Tôi muốn coi thuộc tính này là nơi lưu trữ các thuộc tính (bao gồm các phương thức) của một đối tượng hàm. Đó cũng là lý do tại sao chức năng tiện ích trong JS được định nghĩa như thế Array.prototype.forEach(), Function.prototype.bind(),Object.prototype.toString().

Tại sao phải nhấn mạnh tính chất của một hàm ?

{}.prototype // undefined;
(function(){}).prototype // Object {constructor: function}

// The example above shows object does not have the prototype property.
// But we have Object.prototype, which implies an interesting fact that
typeof Object === "function"
var obj = new Object();

Vì vậy, Arary, Function, Objectlà tất cả các chức năng. Tôi nên thừa nhận rằng điều này làm mới ấn tượng của tôi về JS. Tôi biết các hàm là công dân hạng nhất trong JS nhưng có vẻ như nó được xây dựng trên các hàm.

Sự khác biệt giữa __proto__và là prototypegì?

__proto__một tài liệu tham khảo hoạt động trên mọi đối tượng để tham chiếu đến [[Prototype]]tài sản của nó .

prototypelà một đối tượng được tạo tự động như một thuộc tính đặc biệt của hàm , được sử dụng để lưu trữ các thuộc tính (bao gồm các phương thức) của một đối tượng hàm.

Với hai thứ này, chúng tôi có thể vạch ra một cách tinh thần chuỗi nguyên mẫu. Giống như hình ảnh này minh họa:

function Foo() {}
var b = new Foo();

b.__proto__ === Foo.prototype // true
Foo.__proto__ === Function.prototype // true
Function.prototype.__proto__ === Object.prototype // true

7

 Nguyên mẫu JavaScript so với __prototype__

'use strict'
function A() {}
var a = new A();
class B extends A {}
var b = new B();
console.log('====='); // =====
console.log(B.__proto__ === A); // true
console.log(B.prototype.__proto__ === A.prototype); // true
console.log(b.__proto__ === B.prototype); // true
console.log(a.__proto__ === A.prototype); // true
console.log(A.__proto__ === Function.__proto__); // true
console.log(Object.__proto__ === Function.__proto__); // true
console.log(Object.prototype === Function.__proto__.__proto__); // true
console.log(Object.prototype.__proto__ === null); // true

Trong JavaScript, mọi đối tượng (hàm cũng là đối tượng!) Có một thuộc __proto__tính, thuộc tính được tham chiếu đến nguyên mẫu của nó.

Khi chúng ta sử dụng newtoán tử với hàm tạo để tạo đối tượng mới, thuộc __proto__tính của đối tượng mới sẽ được đặt với thuộc prototypetính của hàm tạo, khi đó hàm tạo sẽ được gọi bởi đối tượng mới, trong quá trình đó "này" sẽ tham chiếu đến đối tượng mới trong phạm vi hàm tạo, cuối cùng trả về đối tượng mới.

Nguyên mẫu của nhà xây dựng là __proto__tài sản, tài sản của nhà xây dựng prototypelà làm việc với newnhà điều hành.

Hàm xây dựng phải là một hàm, nhưng hàm không phải luôn luôn là hàm tạo ngay cả khi nó có thuộc prototypetính.

Chuỗi nguyên mẫu thực sự là thuộc __proto__tính của đối tượng để tham chiếu nguyên mẫu của nó và thuộc tính của nguyên mẫu __proto__để tham chiếu nguyên mẫu của nguyên mẫu, v.v., cho đến khi tham chiếu thuộc tính nguyên mẫu của Object __proto__có liên quan đến null.

Ví dụ:

console.log(a.constructor === A); // true
// "a" don't have constructor,
// so it reference to A.prototype by its ``__proto__`` property,
// and found constructor is reference to A

[[Prototype]]__proto__tài sản thực sự là điều tương tự.

Chúng ta có thể sử dụng phương thức getPrototypeOf của Object để lấy nguyên mẫu.

console.log(Object.getPrototypeOf(a) === a.__proto__); // true

Bất kỳ hàm nào chúng ta viết đều có thể được sử dụng để tạo một đối tượng với newtoán tử, vì vậy bất kỳ ai trong số các hàm đó đều có thể là hàm tạo.


6

Một cách khác để hiểu nó:

var foo = {}

/* 
foo.constructor is Object, so foo.constructor.prototype is actually 
Object.prototype; Object.prototype in return is what foo.__proto__ links to. 
*/
console.log(foo.constructor.prototype === foo.__proto__);
// this proves what the above comment proclaims: Both statements evaluate to true.
console.log(foo.__proto__ === Object.prototype);
console.log(foo.constructor.prototype === Object.prototype);

Chỉ sau khi IE11 __proto__được hỗ trợ. Trước phiên bản đó, chẳng hạn như IE9, bạn có thể sử dụng constructorđể lấy __proto__.


Chỉ có điều tôi sẽ viết nó theo cách khác: foo .__ proto__ === foo.constructor.prototype
epeleg 8/11/2015

6

nguyên mẫu

nguyên mẫu là một tài sản của một chức năng. Đây là kế hoạch chi tiết để tạo các đối tượng bằng cách sử dụng hàm (constructor) đó với từ khóa mới.

__proto__được sử dụng trong chuỗi tra cứu để giải quyết các phương thức, thuộc tính. khi một đối tượng được tạo (sử dụng hàm constructor với từ khóa mới), __proto__được đặt thành (Con constructor ) Function.prototype

function Robot(name) {
    this.name = name;
}
var robot = new Robot();

// the following are true   
robot.__proto__ == Robot.prototype
robot.__proto__.__proto__ == Object.prototype

Dưới đây là lời giải thích (tưởng tượng) của tôi để xóa sự nhầm lẫn:

Hãy tưởng tượng có một lớp tưởng tượng (đồ án / máy cắt coockie) liên quan đến chức năng. Lớp tưởng tượng đó được sử dụng để khởi tạo các đối tượng. prototypelà cơ chế mở rộng (phương thức mở rộng trong C # hoặc Swift Extension) để thêm mọi thứ vào lớp tưởng tượng đó.

function Robot(name) {
    this.name = name;
}

Trên đây có thể được tưởng tượng là:

// imaginary class
class Robot extends Object{

    static prototype = Robot.class  
    // Robot.prototype is the way to add things to Robot class
    // since Robot extends Object, therefore Robot.prototype.__proto__ == Object.prototype

    var __proto__;

    var name = "";

    // constructor
    function Robot(name) {

        this.__proto__ = prototype;
        prototype = undefined;

        this.name = name;
    }

} 

Vì thế,

var robot = new Robot();

robot.__proto__ == Robot.prototype
robot.prototype == undefined
robot.__proto__.__proto__ == Object.prototype

Bây giờ thêm phương thức vào prototypeRobot:

Robot.prototype.move(x, y) = function(x, y){ Robot.position.x = x; Robot.position.y = y};
// Robot.prototype.move(x, y) ===(imagining)===> Robot.class.move(x, y)

Ở trên có thể được tưởng tượng là phần mở rộng của lớp Robot:

// Swift way of extention
extension Robot{
    function move(x, y){    
        Robot.position.x = x; Robot.position.y = y
    }
}

Mà lần lượt,

// imaginary class
class Robot{

    static prototype = Robot.class // Robot.prototype way to extend Robot class
    var __proto__;

    var name = "";

    // constructor
    function Robot(name) {

        this.__proto__ = prototype;
        prototype = undefined;

        this.name = name;
    }

    // added by prototype (as like C# extension method)
    function move(x, y){ 
        Robot.position.x = x; Robot.position.y = y
    };
}

vẫn nghĩ về những cái tên mạch lạc hơn __proto__và nguyên mẫu. có thể nguyên mẫu và thừa kế?
Dmitry

Tôi sẽ nói, prototype__proto__cả hai nên tránh. Chúng tôi có lớp bây giờ và tôi thích OOP.
Hassan Tareq

vấn đề là lớp này tương đối mới và nó không được hỗ trợ bởi các công cụ thực sự tiện lợi như microsoft JScript (rất hay có khi làm việc trên C và cần một công cụ kịch bản nhanh và bẩn luôn ở đó) và javascript (đi kèm với tất cả các bản cài đặt Java mới theo jjs và là một cách hay để đưa Java vào một môi trường năng động thuần túy, nơi bạn không cần phải liên tục biên dịch lại mọi thứ). Vấn đề là nếu lớp là đường, nó sẽ không thành vấn đề, nhưng không, nó cung cấp những thứ không thể có nếu không có chúng trong các phiên bản js cũ. Giống như mở rộng "Chức năng".
Dmitry

Cuối cùng, chúng tôi sẽ nhận được hỗ trợ. Tôi là nhà phát triển phụ trợ, vì vậy tôi không gặp vấn đề gì, tôi hiếm khi viết mã trong js.
Hassan Tareq

và kế thừa các thành viên tĩnh theo cách thêm / xóa thành viên tĩnh khỏi cha mẹ được chú ý bởi trẻ (mà tôi không thể nghĩ ra cách nào để thực hiện trên JScript, điều này không cung cấp Object.assign / __ proto __ / getPrototypeOf, vì vậy bạn phải sửa lại đối tượng gốc Object.prototype để mô phỏng nó)
Dmitry

4

Nói một cách đơn giản:

> var a = 1
undefined
> a.__proto__
[Number: 0]
> Number.prototype
[Number: 0]
> Number.prototype === a.__proto__
true

Điều này cho phép bạn đính kèm các thuộc tính vào các đối tượng X.prototype SAU loại X đã được khởi tạo và chúng vẫn sẽ có quyền truy cập vào các thuộc tính mới đó thông qua tham chiếu __proto__ mà công cụ Javascript sử dụng để đi lên chuỗi nguyên mẫu.


4

Prototype hoặc Object.prototype là một thuộc tính của một đối tượng theo nghĩa đen. Nó đại diện cho đối tượng nguyên mẫu Object mà bạn có thể ghi đè để thêm nhiều thuộc tính hoặc phương thức hơn nữa dọc theo chuỗi nguyên mẫu.

__proto__ là một thuộc tính accessor (hàm get và set) hiển thị nguyên mẫu bên trong của một đối tượng thông qua nó được truy cập.

Người giới thiệu:

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
  2. http://www.w3schools.com/js/js_object_prototypes.asp

  3. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto


Object.prototypekhông phải là một tài sản của một đối tượng theo nghĩa đen, cố gắng in ra {}.prototypetrả về không xác định; tuy nhiên, nó có thể được truy cập thông qua {}.__proto__, trả về Object.prototype.
doubleOrt

3

Tôi biết, tôi đến muộn nhưng hãy để tôi cố gắng đơn giản hóa nó.

Hãy để chúng tôi nói có một chức năng

    function Foo(message){

         this.message = message ; 
     };

     console.log(Foo.prototype);

Hàm Foo sẽ có một đối tượng nguyên mẫu được liên kết. Vì vậy, bất cứ khi nào chúng ta tạo một hàm trong JavaScript, nó luôn có một đối tượng nguyên mẫu được liên kết với nó.

Bây giờ chúng ta hãy tiếp tục và tạo hai đối tượng bằng hàm Foo.

    var a = new Foo("a");
    var b = new Foo("b");
    console.log(a.message);
    console.log(b.message);
  1. Bây giờ chúng ta có hai đối tượng, đối tượng a và đối tượng b. Cả hai đều được tạo bằng cách sử dụng hàm tạo Foo. Hãy ghi nhớ nhà xây dựng chỉ là một từ ở đây.
  2. Đối tượng a và b đều có một bản sao thuộc tính tin nhắn.
  3. Hai đối tượng a và b được liên kết với đối tượng nguyên mẫu của hàm tạo Foo.
  4. Trên các đối tượng a và b, chúng ta có thể truy cập nguyên mẫu Foo bằng thuộc tính proto trong tất cả các trình duyệt và trong IE, chúng ta có thể sử dụng Object.getPrototypeOf (a) hoặc Object.getPrototypeOf (b)

Bây giờ, Foo.prototype, a. proto , và b. proto tất cả biểu thị cùng một đối tượng.

    b.__proto__ === Object.getPrototypeOf(a);
    a.__proto__ ===  Foo.prototype;
    a.constructor.prototype  === a.__proto__;

tất cả những điều trên sẽ trở lại đúng sự thật.

Như chúng ta biết, trong các thuộc tính JavaScript có thể được thêm động. Chúng ta có thể thêm tài sản vào đối tượng

    Foo.prototype.Greet = function(){

         console.log(this.message);
    }
    a.Greet();//a
    b.Greet();//b
    a.constructor.prototype.Greet();//undefined 

Như bạn thấy, chúng tôi đã thêm phương thức Greet () trong Foo.prototype nhưng nó có thể truy cập được trong a và b hoặc bất kỳ đối tượng nào khác được xây dựng bằng Foo.

Trong khi thực hiện a.Greet (), trước tiên JavaScript sẽ tìm kiếm Greet trong đối tượng a trên danh sách thuộc tính. Khi không tìm thấy, nó sẽ đi lên trong chuỗi proto của a. Từ một. proto và Foo.prototype là cùng một đối tượng, JavaScript sẽ tìm phương thức Greet () và thực thi nó.

Tôi hy vọng, bây giờ nguyên mẫu và proto được đơn giản hóa một chút.


3

Ví dụ giải thích:

function Dog(){}
Dog.prototype.bark = "woof"

let myPuppie = new Dog()

bây giờ, myPupppie có thuộc __proto__tính trỏ đến Dog.prototype.

> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}

nhưng myPuppie KHÔNG có thuộc tính nguyên mẫu.

> myPuppie.prototype
>> undefined

Vì vậy, __proto__mypuppie là tham chiếu đến thuộc tính .prototype của hàm tạo được sử dụng để khởi tạo đối tượng này (và đối tượng myPuppie hiện tại có "mối quan hệ" với __proto__đối tượng này ), trong khi thuộc tính .prototype của myPuppie chỉ đơn giản là không có (vì chúng tôi đã không đặt nó).

Giải thích hay của MPJ tại đây: proto vs nguyên mẫu - Tạo đối tượng trong JavaScript


3

Tôi đã tạo cho mình một bản vẽ nhỏ thể hiện đoạn mã sau:

var Cat = function() {}
var tom = new Cat()

Hiểu __proto__ và nguyên mẫu

Tôi có một nền tảng OO cổ điển, vì vậy thật hữu ích khi thể hiện hệ thống phân cấp theo cách này. Để giúp bạn đọc sơ đồ này, hãy coi các hình chữ nhật trong ảnh là các đối tượng JavaScript. Và vâng, chức năng cũng là đối tượng. ;)

Các đối tượng trong JavaScript có các thuộc tính và __proto__chỉ là một trong số chúng.

Ý tưởng đằng sau đặc tính này là chỉ đến đối tượng tổ tiên trong hệ thống phân cấp (thừa kế).

Đối tượng gốc trong JavaScript là Object.prototypevà tất cả các đối tượng khác là hậu duệ của đối tượng này. Các __proto__tài sản của đối tượng gốc là null, đại diện cuối chuỗi thừa kế.

Bạn sẽ nhận thấy đó prototypelà một tài sản của các chức năng. Catlà một hàm, nhưng cũng FunctionObjectlà các hàm (nguyên gốc). tomkhông phải là một chức năng, do đó nó không có thuộc tính này.

Ý tưởng đằng sau thuộc tính này là trỏ đến một đối tượng sẽ được sử dụng trong xây dựng, tức là khi bạn gọi newtoán tử trên hàm đó.

Lưu ý rằng các đối tượng nguyên mẫu (hình chữ nhật màu vàng) có một thuộc tính khác được gọi là constructorđiểm quay lại đối tượng hàm tương ứng. Vì lý do ngắn gọn, điều này đã không được mô tả.

Thật vậy, khi chúng ta tạo tomđối tượng với new Cat(), đối tượng được tạo sẽ có thuộc __proto__tính được đặt thành prototypeđối tượng của hàm xây dựng.

Cuối cùng, chúng ta hãy chơi với sơ đồ này một chút. Các tuyên bố sau là đúng:

  • tom.__proto__tài sản trỏ đến cùng một đối tượng như Cat.prototype.

  • Cat.__proto__chỉ vào Function.prototypeđối tượng, chỉ thích Function.__proto__Object.__proto__làm.

  • Cat.prototype.__proto__tom.__proto__.__proto__trỏ đến cùng một đối tượng và đó là Object.prototype.

Chúc mừng!


Giải thích rất tốt!
Giao diện người dùng StackOverflow

@theshinylight, tom.__proto__Cat.prototypehoàn toàn bình đẳng, Vì vậy, tom.__proto__ === Cat.prototypeCat.prototype === tom.__proto__là sự thật. Vì vậy, ý của bạn là gì bởi mũi tên trong hình ảnh ??
aXuser264

Mũi tên đen (nếu bạn đang đề cập đến nó) không có ý nghĩa cụ thể, ngoài tài sản của đối tượng. Vì vậy, prototypelà tài sản của Catđối tượng (từ câu hỏi của bạn).
thesh502ight

2

ĐỊNH NGHĨA

(số bên trong dấu ngoặc đơn () là một 'liên kết' đến mã được viết bên dưới)

prototype- một đối tượng bao gồm:
=> các hàm (3) của đặc biệt này ConstructorFunction.prototype(5) có thể truy cập được bởi mỗi đối tượng (4) được tạo hoặc được tạo thông qua hàm xây dựng này (1)
=> chính hàm xây dựng (1) )
=> __proto__của đối tượng cụ thể này (đối tượng nguyên mẫu)

__proto__(dandor proto?) - một liên kết GIỮA bất kỳ đối tượng nào (2) được tạo thông qua một hàm xây dựng cụ thể (1), VÀ các thuộc tính của đối tượng nguyên mẫu (5) của hàm tạo đó THAT cho phép mỗi đối tượng được tạo (2) có quyền truy cập vào các chức năng của nguyên mẫu và các phương thức (4) ( __proto__theo mặc định được bao gồm trong mọi đối tượng đơn lẻ trong JS)

XÁC NHẬN MÃ

1.

    function Person (name, age) {
        this.name = name;
        this.age = age;} 

2.

    var John = new Person(‘John’, 37);
    // John is an object

3.

    Person.prototype.getOlder = function() {
        this.age++;
    }
    // getOlder is a key that has a value of the function

4.

    John.getOlder();

5.

    Person.prototype;

1

Tôi sẽ thử một lời giải thích lớp 4:

Mọi thứ rất đơn giản. A prototypelà một ví dụ về cách một cái gì đó nên được xây dựng. Vì thế:

  • Tôi là một functionvà tôi xây dựng các đối tượng mới tương tự như của tôiprototype

  • Tôi là một objectvà tôi được xây dựng bằng cách sử dụng của tôi __proto__làm ví dụ

bằng chứng :

function Foo() { }

var bar = new Foo()

// `bar` is constructed from how Foo knows to construct objects
bar.__proto__ === Foo.prototype // => true

// bar is an instance - it does not know how to create objects
bar.prototype // => undefined

1
Không, không phải prototypecũng không __proto__được sử dụng bất cứ lúc nào như một bản thiết kế hay để tạo ra bất kỳ đối tượng nào. Đây là một huyền thoại được giới thiệu bởi classcú pháp mờ và nó là tiền thân của nó. Như bài trả lời cho biết nó chỉ được sử dụng cho chuỗi tra cứu và trong trường hợp prototypexác định constructorđược sử dụng với new(đó là một phần của cơ chế giả vờ đẳng cấp đó gây nhầm lẫn cho nhiều người dùng trong đó có tôi).
Christof Kälin

Điểm đầu tiên phải là "Tôi là một chức năng và tôi xây dựng các đối tượng mới sẽ ủy thác cho nguyên mẫu của tôi"
Nitin Jadhav

1

Mỗi hàm bạn tạo đều có một thuộc tính được gọi prototypevà nó bắt đầu cuộc sống như một đối tượng trống rỗng. Thuộc tính này không được sử dụng cho đến khi bạn sử dụng chức năng này làm chức năng xây dựng tức là với từ khóa 'mới'.

Điều này thường bị nhầm lẫn với __proto__tài sản của một đối tượng. Một số có thể bị nhầm lẫn và ngoại trừ rằng thuộc prototypetính của một đối tượng có thể khiến chúng trở thành proto của một đối tượng. Nhưng đây không phải là trường hợp. prototypeđược sử dụng để lấy __proto__đối tượng được tạo từ hàm tạo.

Trong ví dụ trên:

function Person(name){
    this.name = name
}; 

var eve = new Person("Eve");

console.log(eve.__proto__ == Person.prototype) // true
// this is exactly what prototype does, made Person.prototype equal to eve.__proto__

Tôi hy vọng nó có ý nghĩa.


1
prototypekhông được sử dụng để tạo ra __proto__một đối tượng. __proto__, khi được truy cập, chỉ cung cấp một tham chiếu đến prototypeđối tượng.
doubleOrt

1

Điều gì về việc sử dụng __proto__cho các phương thức tĩnh?

function Foo(name){
  this.name = name
  Foo.__proto__.collection.push(this)
  Foo.__proto__.count++

}

Foo.__proto__.count=0
Foo.__proto__.collection=[]

var bar = new Foo('bar')
var baz = new Foo('baz')

Foo.count;//2
Foo.collection // [{...}, {...}]
bar.count // undefined

Đó chính xác là lý do tại sao một câu trả lời cho " __proto__VS. prototypetrong JavaScript" ?
Andreas

nó tốt hay sao về Foo.collection.push (cái này) Foo.count ++
Selva Ganapathi

1

(function(){ 
      let a = function(){console.log(this.b)};
      a.prototype.b = 1;
      a.__proto__.b = 2;
      let q = new a();
      console.log(a.b);
      console.log(q.b) 
    })()

Hãy thử mã này để hiểu


1

Chỉ có một đối tượng được sử dụng cho chuỗi protypal. Đối tượng này rõ ràng có một tên và một giá trị: __proto__là tên của nó, và prototypelà giá trị của nó. Đó là tất cả.

để dễ nắm bắt hơn, hãy nhìn vào sơ đồ trên đầu bài này (Sơ đồ của dmitry soshnikov), bạn sẽ không bao giờ tìm thấy __proto__điểm nào khác ngoài prototypegiá trị của nó.

Ý chính là đây: __proto__là tên tham chiếu đến đối tượng nguyên mẫu và prototypelà đối tượng nguyên mẫu thực tế.

Nó giống như nói:

let x = {name: 'john'};

xlà tên đối tượng (con trỏ) và {name: 'john'}là đối tượng thực tế (giá trị dữ liệu).

LƯU Ý: đây chỉ là một gợi ý đơn giản hóa ồ ạt về cách chúng có liên quan ở mức cao.

Cập nhật: Dưới đây là một ví dụ javascript cụ thể để minh họa rõ hơn:

let x = new String("testing") // Or any other javascript object you want to create

Object.getPrototypeOf(x) === x.__proto__; // true

Điều này có nghĩa rằng khi Object.getPrototypeOf(x)được chúng ta những giá trị thực tế x(đó là nguyên mẫu của nó), là chính xác những gì __proto__của xtrỏ đến. Do đó, __proto__thực sự là chỉ vào nguyên mẫu của x. Do đó, __proto__tham chiếu x(con trỏ của x) và prototypelà giá trị của x(nguyên mẫu của nó).

Tôi hy vọng nó một chút rõ ràng bây giờ.


1

Đây là một câu hỏi rất quan trọng liên quan đến bất cứ ai muốn hiểu sự kế thừa nguyên mẫu. Theo những gì tôi hiểu, nguyên mẫu được gán theo mặc định khi một đối tượng được tạo mới từ một hàm vì Hàm có đối tượng nguyên mẫu theo định nghĩa:

function protofoo(){
}
var protofoo1 = new protofoo();
console.log(protofoo.prototype.toString()); //[object Object]

Khi chúng ta tạo một đối tượng bình thường mà không có mới, tức là rõ ràng từ một hàm, nó không có nguyên mẫu nhưng nó có một proto trống có thể được gán một nguyên mẫu.

var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo

Chúng ta có thể sử dụng Object.create để liên kết một đối tượng một cách rõ ràng.

// we can create `bar` and link it to `foo`
var bar = Object.create( foo );
bar.fooprops= "We checking prototypes";
console.log(bar.__proto__); // "foo"
console.log(bar.fooprops); // "We checking prototypes"
console.log(bar.check); // 10 is delegated to `foo`

0

__proto__là cơ sở để xây dựng prototypevà một hàm xây dựng, ví dụ: function human(){}has prototypeđược chia sẻ thông qua __proto__trong thể hiện mới của hàm tạo. Đọc chi tiết hơn tại đây


@Derick Daniel: không chắc tại sao bạn lại bỏ phiếu này nhưng bản chỉnh sửa bạn thực hiện không phải là tôi đang cố gắng truyền đạt. Chỉnh sửa nó thêm để giải phóng mặt bằng :).
Jyoti Duhan

Jyoti, tôi đã không bỏ phiếu cho câu trả lời của bạn, một người khác đã làm, tôi chỉ chỉnh sửa nó :)
Freelancer

0

Như điều này đã đúng

__proto__là đối tượng thực tế được sử dụng trong chuỗi tra cứu để giải quyết các phương thức, v.v. nguyên mẫu là đối tượng được sử dụng để xây dựng __proto__khi bạn tạo một đối tượng mới:

( new Foo ).__proto__ === Foo.prototype;
( new Foo ).prototype === undefined;

Chúng ta có thể lưu ý thêm rằng __proto__thuộc tính của một đối tượng được tạo bằng cách sử dụng hàm xây dựng điểm hướng tới vị trí bộ nhớ được chỉ hướng bởi thuộc tính nguyên mẫu của hàm tạo tương ứng đó.

Nếu chúng ta thay đổi vị trí bộ nhớ của nguyên mẫu hàm xây dựng, __proto__đối tượng dẫn xuất vẫn sẽ tiếp tục hướng về không gian địa chỉ gốc. Do đó, để làm cho thuộc tính chung có sẵn trong chuỗi thừa kế, luôn luôn thêm thuộc tính vào nguyên mẫu hàm xây dựng , thay vì khởi tạo lại nó (sẽ thay đổi địa chỉ bộ nhớ của nó).

Hãy xem xét ví dụ sau:

function Human(){
    this.speed = 25;
}

var himansh = new Human();

Human.prototype.showSpeed = function(){
    return this.speed;
}

himansh.__proto__ === Human.prototype;  //true
himansh.showSpeed();    //25

//now re-initialzing the Human.prototype aka changing its memory location
Human.prototype = {lhs: 2, rhs:3}

//himansh.__proto__ will still continue to point towards the same original memory location. 

himansh.__proto__ === Human.prototype;  //false
himansh.showSpeed();    //25

-1

sự hiểu biết của tôi là: __proto__ và nguyên mẫu đều được phục vụ cho kỹ thuật chuỗi nguyên mẫu. sự khác biệt là các hàm được đặt tên bằng dấu gạch dưới (như __proto__) không nhằm mục đích cho các nhà phát triển được gọi một cách rõ ràng. nói cách khác, chúng chỉ dành cho một số cơ chế như kế thừa, v.v. chúng là 'back-end'. nhưng các hàm được đặt tên không có dấu gạch dưới được thiết kế để gọi một cách rõ ràng, chúng là 'front-end'.


3
Có nhiều hơn __proto__prototype, hơn chỉ là quy ước đặt tên. Họ có thể hoặc không thể chỉ đến cùng một đối tượng. Xem câu trả lời @hotlus.
demisx

1
@demisx tất nhiên bạn nói là đúng, nhưng ý kiến ​​của tôi là sự khác biệt tên phơi bày sự tương phản của chức năng.
Beicai

Nó không đủ để nói "theo sự hiểu biết của bạn", đặc biệt là khi các câu trả lời hay khác đã được cung cấp trước đó ...
ProfNandaa

-3

!!! ĐÂY LÀ GIẢI THÍCH TỐT NHẤT TRÊN THẾ GIỚI !!!!!

var q = {}
var prototype = {prop: 11}

q.prop // undefined
q.__proto__ = prototype
q.prop // 11

trong hàm tạo, công cụ javascript tự động gọi nó q.__proto__ = prototypekhi chúng ta viết new Classvà vào bộ __proto__propClass.prototype

function Class(){}
Class.prototype = {prop: 999} // set prototype as we need, before call new

var q = new Class() // q.__proto__ = Class.prototype
q.prop // 999

Thưởng thức %)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.