2009-03-16 5 views
145
function Gadget(name, color) 
{ 
    this.name = name; 
    this.color = color; 
} 

Gadget.prototype.rating = 3 

var newtoy = new Gadget("webcam", "black") 

newtoy.constructor.prototype.constructor.prototype.constructor.prototype 

Nó luôn luôn trả về đối tượng với giá = 3.Làm thế nào để __proto__ khác với constructor.prototype?

Nhưng nếu tôi làm như sau:

newtoy.__proto__.__proto__.__proto__ 

Chuỗi kết thúc lên trở null.

Cũng trong Internet Explorer, làm cách nào để kiểm tra giá trị rỗng nếu không có thuộc tính __proto__?

+28

[Sơ đồ đồ thị] (http://i.imgur.com/IkxPv.png) này sẽ giúp bạn hiểu sự khác biệt giữa nguyên mẫu và __proto__. Bạn có thể theo chuỗi __proto__ từ đối tượng newtoy, và sau đó bạn sẽ nhận ra lý do tại sao __Proto__ thứ 3 từ newtoy là null. – bits

+0

Cũng rõ ràng từ sơ đồ 'newtoy.prototype' không bằng' newtoy.constructor.prototype' và do đó 'newtoy.constructor.prototype' sẽ không có thuộc tính được gọi là' rating'. Tương tự 'newtoy.constructor.prototype.constructor.property' cũng sẽ không có thuộc tính được gọi là' rating'. – bits

+0

Typo trong nhận xét cuối cùng: do đó 'newtoy.constructor.prototype' sẽ có thuộc tính được gọi là xếp hạng. Tương tự 'newtoy.constructor.prototype.constructor.property' cũng sẽ có thuộc tính được gọi là rating. – bits

Trả lời

182

Tôi đã cố gắng để quấn quanh đầu tôi này thời gian gần đây và cuối cùng đã đưa ra với điều này "bản đồ" mà tôi nghĩ rằng nhà kho ánh sáng đầy đủ trong vấn đề

http://i.stack.imgur.com/KFzI3.png enter image description here

Tôi biết tôi không phải là người đầu tiên làm điều này nhưng nó là thú vị hơn figuring nó ra rằng việc tìm kiếm nó :-). Dù sao, sau đó tôi tìm thấy ví dụ này một sơ đồ mà tôi nghĩ rằng nói về cơ bản giống nhau:

Javascript object layout

Điều đáng ngạc nhiên nhất đối với tôi là phát hiện ra rằng Object.__proto__ điểm để Function.prototype, thay vì Object.prototype, nhưng tôi chắc chắn có một lý do chính đáng cho điều đó: -)

Tôi cũng dán mã được đề cập trong hình ảnh ở đây cũng như nếu có ai muốn thử nghiệm. Lưu ý rằng một số tính chất được bổ sung vào đối tượng để làm dễ dàng để biết nơi mà chúng tôi đang theo đuổi một số bước nhảy:

Object.O1=''; 
Object.prototype.Op1=''; 

Function.F1 = ''; 
Function.prototype.Fp1 = ''; 

Cat = function(){}; 
Cat.C1 = ''; 
Cat.prototype.Cp1 = ''; 

mycat = new Cat(); 
o = {}; 

// EDITED: using console.dir now instead of console.log 
console.dir(mycat); 
console.dir(o); 
+0

Sơ đồ tuyệt vời - thực sự giúp hình dung mọi thứ! Tôi đã bình chọn câu trả lời này, vì vậy bạn sẽ có thể đính kèm hình ảnh ngay bây giờ. :) – hopper

+0

Xong, cảm ơn phễu :-) – drodsou

+2

@utsaina Rất tuyệt. Kiểm tra [biểu diễn đồ họa] khác (http://i.imgur.com/IkxPv.png) của mã OP được đăng. Và tôi nghĩ rằng các sơ đồ của chúng tôi đã được thỏa thuận về mặt chi tiết kỹ thuật. – bits

63

constructor là thuộc tính [[DontEnum]] được xác định trước của đối tượng được trỏ đến bởi thuộc tính prototype của đối tượng hàm và ban đầu sẽ trỏ đến đối tượng hàm.

__proto__ tương đương với thuộc tính [[Prototype]] bên trong của một đối tượng, ví dụ như mẫu thử nghiệm thực tế của nó.

Khi bạn tạo đối tượng với toán tử new, thuộc tính [[Prototype]] bên trong của nó sẽ được đặt thành đối tượng được chỉ định bởi thuộc tính prototype của hàm tạo.

Điều này có nghĩa là .constructor sẽ đánh giá là .__proto__.constructor, tức là hàm tạo được sử dụng để tạo đối tượng và như chúng ta đã biết, thuộc tính protoype của hàm này được sử dụng để đặt [[Prototype] của đối tượng.

Sau .constructor.prototype.constructor giống hệt với .constructor (miễn là các thuộc tính này chưa bị ghi đè); xem here để có giải thích chi tiết hơn.

Nếu __proto__ khả dụng, bạn có thể đi bộ chuỗi nguyên mẫu thực tế của đối tượng. Không có cách nào để làm điều này trong ECMAScript3 đơn giản vì JavaScript không được thiết kế cho các cấu trúc thừa kế sâu.

+1

Liên kết 'ở đây' là tiêu chuẩn vàng. Đến đó nếu bạn muốn mô tả đầy đủ. – Ricalsin

+0

Bắt tốt với chuỗi '.constructor.prototype'. Tôi cũng không rõ ràng với tôi, trong khi tôi không thấy rằng '.constructor' là bằng' .__ proto __. Constructor'. Điều đó đơn giản có nghĩa là đi xe đạp giữa hàm xây dựng và nguyên mẫu của nó. –

11

Object là Eve, và Function là Adam, Adam (Function) sử dụng xương của mình (Function.prototype) để tạo Eve (Object).Sau đó, ai đã tạo ra Adam (Function)? - Nhà phát minh ngôn ngữ JavaScript :-).

Theo câu trả lời của utsaina, tôi muốn thêm thông tin hữu ích hơn.

Điều đáng ngạc nhiên nhất đối với tôi là phát hiện ra rằng Object.__proto__ điểm để Function.prototype, thay vì Object.prototype, nhưng tôi chắc chắn có một lý do chính đáng cho điều đó :-)

nó không nên . Object.__proto__ KHÔNG được trỏ đến Object.prototype. Thay vào đó, bản sao của Objecto, o.__proto__ phải trỏ đến Object.prototype.

(Forgive me cho việc sử dụng các điều khoản classinstance trong JavaScript, nhưng bạn biết nó :-)

Tôi nghĩ lớp Object chính nó là một thể hiện của Function, đó là lý do tại sao Object.__proto__ === Function.prototype. Do đó: Object là Eve và Function là Adam, Adam (Function) sử dụng xương của mình (Function.prototype) để tạo Eve (Object).

Hơn nữa, ngay cả những lớp Function chính nó là một thể hiện của Function bản thân, đó là Function.__proto__ === Function.prototype, đó cũng là lý do tại sao Function === Function.constructor

Tiếp tục hơn nữa, lớp thường xuyên Cat là một thể hiện của Function, đó là Cat.__proto__ === Function.prototype.

Lý do ở trên là khi chúng tôi tạo một lớp trong JavaScript, trên thực tế, chúng tôi chỉ tạo một hàm, hàm này phải là một phiên bản Function. ObjectFunction chỉ là đặc biệt, nhưng chúng vẫn là lớp học, trong khi Cat là một lớp thông thường.

Như một vấn đề của yếu tố, trong công cụ JavaScript của Google Chrome, sau 4:

  • Function.prototype
  • Function.__proto__
  • Object.__proto__
  • Cat.__proto__

Họ là tất cả === (hoàn toàn bình đẳng) đến 3 khác, và giá trị của họ là function Empty() {}

> Function.prototype 
    function Empty() {} 
> Function.__proto__ 
    function Empty() {} 
> Object.__proto__ 
    function Empty() {} 
> Cat.__proto__ 
    function Empty() {} 
> Function.prototype === Function.__proto__ 
    true 
> Function.__proto__ === Object.__proto__ 
    true 
> Object.__proto__ === Cat.__proto__ 
    true 

OK. Sau đó, ai tạo ra đặc biệt function Empty() {} (Function.prototype)? Hãy suy nghĩ về nó :-)

+0

Đồng ý với điều đó, ngoại trừ điều cuối cùng: chức năng 'Empty() {}' bạn tham chiếu bằng Function.prototype, vv ?, mã bạn sử dụng trong chrome là gì console? – drodsou

+2

Tôi đã sửa chữa điều cuối cùng mà bạn đã chỉ ra. Giá trị của chúng là 'hàm Empty() {}' trong Google Chrome. Tôi cũng đã thêm đầu ra giao diện điều khiển. –

+0

tất cả các hàm là instanceof Function, và do đó, tất cả các hàm được kế thừa ('_ _proto_ _') từ Function.prototype. Nó đơn giản như vậy :) – xorcus

28

Kế thừa nguyên mẫu trong JavaScript dựa trên thuộc tính __proto__ theo nghĩa là mỗi đối tượng kế thừa nội dung của đối tượng được tham chiếu bởi thuộc tính __proto__ của nó.

Thuộc tính prototype chỉ dành riêng cho các đối tượng Function và chỉ khi sử dụng new toán tử để gọi số Function làm hàm tạo. Trong trường hợp này, đối tượng được tạo là __proto__ sẽ được đặt thành số Function.prototype của hàm tạo.

Điều này có nghĩa là thêm vào Function.prototype sẽ tự động phản ánh trên tất cả các đối tượng có __proto__ đang tham chiếu Function.prototype.

Thay thế nhà xây dựng Function.prototype bằng một đối tượng khác sẽ không cập nhật __proto__ thuộc tính cho bất kỳ đối tượng hiện có nào.

Lưu ý rằng không nên truy cập trực tiếp __proto__ thuộc tính, thay vào đó, sử dụng Object.getPrototypeOf(object).

Để trả lời câu hỏi đầu tiên, tôi đã tạo một biểu đồ riêng biệt của các tham chiếu __proto__prototype, không may cho phép tôi thêm hình ảnh với "ít hơn 10 danh tiếng". Có lẽ một thời gian khác.

[Chỉnh sửa] Con số này sử dụng [[Prototype]] thay vì __proto__ vì đó là cách đặc tả ECMAScript đề cập đến các đối tượng bên trong. Tôi hy vọng bạn có thể tìm ra mọi thứ.

Dưới đây là một số gợi ý để giúp bạn hiểu con số này:

red = JavaScript Function constructor and its prototype 
violet = JavaScript Object constructor and its prototype 
green = user-created objects 
     (first created using Object constructor or object literal {}, 
      second using user-defined constructor function) 
blue = user-defined function and its prototype 
     (when you create a function, two objects are created in memory: 
      the function and its prototype) 

Lưu ý rằng constructor tài sản không tồn tại trong các đối tượng được tạo ra, nhưng được thừa hưởng từ nguyên mẫu.

enter image description here

+1

Tôi đã bình chọn câu trả lời của bạn, vì vậy bạn nên có ít nhất 10 danh tiếng ngay bây giờ. Tôi rất muốn xem sơ đồ của bạn. Nó có lẽ sẽ thêm vào khía cạnh hơi khó hiểu và không được tài liệu hóa của JS. – pseudosavant

+0

u có thể tải lên sơ đồ – Nav

+0

Câu trả lời rõ ràng nhất. Cảm ơn bạn. – clime

2

Mọi chức năng tạo nguyên mẫu. Và khi chúng ta tạo một đối tượng bằng cách sử dụng hàm tạo hàm đó thì thuộc tính __proto__ của đối tượng của tôi sẽ bắt đầu trỏ đến nguyên mẫu của hàm đó.

+1

Tôi nghĩ bạn muốn nói thuộc tính '__proto__'. – demisx

+0

Có. Tôi có nghĩa là __proto__ tài sản của một đối tượng. Tôi hy vọng thông tin này hữu ích. –

4

Tôi thực sự không biết tại sao mọi người không sửa chữa bạn về vấn đề thực tế trong sự hiểu biết của bạn.

này sẽ làm cho dễ dàng hơn rất nhiều cho bạn để phát hiện các vấn đề

Vì vậy, chúng ta hãy xem những gì đang xảy ra:

var newtoy = new Gadget("webcam", "black") 

newtoy 
    .constructor //newtoy's constructor function is newtoy (the function itself) 
    .prototype // the function has a prototype property.(all functions has) 
     .constructor // constructor here is a **property** (why ? becuase you just did `prototype.constructor`... see the dot ?) ! it is not(!) the constructor function !!! this is where your mess begins. it points back to the constructor function itself (newtoy function) 
     .prototype // so again we are at line 3 of this code snippet 
      .constructor //same as line 4 ... 
       .prototype 
       rating = 3 

Tuyệt vời, vì vậy bây giờ chúng ta hãy xem xét điều này __proto__

Trước đó, hãy nhớ 2 điều về __proto__:

  1. Khi bạn tạo một đối tượng với toán tử new, thuộc tính nội bộ [[Prototype]]/proto__ của nó sẽ được đặt thành thuộc tính prototype (1) của số constructor function hoặc "người tạo" nếu bạn muốn.

  2. Được mã hóa cứng trong JS -: Object.prototype.__proto__null.

Hãy tham khảo những 2 điểm là "bill"

newtoy 
    .__proto__ // When `newtoy` was created , Js put __proto__'s value equal to the value of the cunstructor's prototype value. which is `Gadget.prototype`. 
     .__proto__ // Ok so now our starting point is `Gadget.prototype`. so regarding "bill" who is the constructor function now? watch out !! it's a simple object ! a regular object ! prototype is a regular object!! so who is the constructor function of that object ? Right , it's the `function Object(){...}`. Ok .(continuing "bill") does it has a `prototype` property ? sure. all function has. it's `Object.prototype`. just remember that when Gadget.prototype was created , it's internal `__proto__` was refered to `Object.prototype` becuase as "bill" says :"..will be set to the `prototype` property of its `constructor function`" 
      .__proto__ // Ok so now our satrting point is `Object.prototype`. STOP. read bullet 2.Object.prototype.__proto__ is null by definition. when Object.prototype (as an object) was created , they SET THE __PROTO__ AS NULL HARDCODED 

tốt hơn?