2013-03-05 23 views
5

Tôi khá mới sử dụng object.create thay vì cách js cổ điển để đạt được thừa kế nguyên mẫu.Object.create setting __proto__ nhưng không phải là nguyên mẫu

Trong Chrome ít nhất tôi đã ngạc nhiên khi nhìn thấy đoạn mã sau:

var baseObject = { 
test : function(){ 
    console.log('Child'); 
} 
} 

var newObject = Object.create(baseObject); 
newObject.test = function(){ 
console.log('Parent'); 
this.__proto__.test(); 
} 
console.log(newObject); 

newObject.test(); 

Tạo này (mô phỏng đầu ra trong các công cụ web):

Object {test: function, test: function} 
    test: function(){ 
    __proto__: Object 
     test: function(){ 
     __proto__: Object 
Parent 
Child 

Vì vậy, bạn thấy nó không thiết lập nguyên mẫu nhưng thay vào đó chỉ "__proto__", điều mà tôi nghĩ là không được khuyến khích trong việc sử dụng nó. Bạn có thể thấy rằng trong mã của tôi tôi có thể kế thừa đúng, và gọi đối tượng cha, nhưng chỉ sử dụng "__proto__". Sử dụng "nguyên mẫu" dẫn đến lỗi (không xác định).

Điều gì đang xảy ra ở đây? Tôi figured object.create sẽ thiết lập "nguyên mẫu" thay vì đó là tiêu chuẩn (hoặc vì vậy tôi đã giả định). Tại sao nó phổ biến và làm cho tôi sử dụng "__proto__"

Trả lời

5

Không sử dụng __proto__ để thiết lập thừa kế nguyên mẫu của bạn không được khuyến khích vì nó không chuẩn. Điều đó không có nghĩa là bạn không thể sử dụng Object.create() để tạo một đối tượng mới với một đối tượng nguyên mẫu cụ thể.

Đối tượng không có thuộc tính .prototype theo mặc định. Bạn đang bối rối đối tượng .prototype của một hàm.

Vì vậy, nếu tôi có một chức năng như thế này:

function Foo() { 

} 

Đó Foo đối tượng chức năng có một tài sản tham chiếu đến một đối tượng mà sẽ được sử dụng như là __proto__ của bất kỳ đối tượng được tạo khi viện dẫn như một constructor .prototype.

var f = new Foo(); 

Bây giờ f là một đối tượng với Foo.prototype trong chuỗi nguyên mẫu của nó. Bạn có thể xác minh điều này bằng cách sử dụng Object.getPrototypeOf();

Object.getPrototypeOf(f) === Foo.prototype; // true 

Object.create mang đến cho bạn là khả năng thiết lập các chuỗi nguyên mẫu giống nhau, nhưng mà không sử dụng một hàm constructor. Vì vậy, điều này sẽ là tương đương.

var f2 = Object.create(Foo.prototype); 

Bây giờ chúng tôi có một đối tượng được thiết lập giống như đối tượng gốc f.

Object.getPrototypeOf(f2) === Foo.prototype;   // true 
Object.getPrototypeOf(f2) === Object.getPrototypeOf(f); // true 

Vì vậy, nó chỉ là một cách khác nhau làm những gì là cuối cùng điều tương tự. Mối quan hệ giữa một đối tượng và chuỗi nguyên mẫu của nó là mối quan hệ nội bộ. Số phi tiêu chuẩn __proto__ chỉ phơi bày mối quan hệ đó.

+0

Rất thú vị. Bạn đúng Tôi quên nguyên mẫu chỉ áp dụng cho các chức năng. Vì vậy, về cơ bản, ít nhất là chrome, việc sử dụng __proto__ loại nguyên mẫu sao chép cho các đối tượng kế hoạch một cách không chuẩn? – nahelm

+0

@nahelm: Sắp xếp. '__proto__' cho phép bạn cung cấp cho một đối tượng hiện có một chuỗi nguyên mẫu mới. Hàm xây dựng và 'Object.create' chỉ cho phép bạn thiết lập nó tại thời điểm đối tượng được tạo. Từ đó nó vĩnh viễn. Trong thực tế, nếu bạn tạo một đối tượng từ hàm constructor, thì bạn cung cấp cho hàm constructor một đối tượng '.prototype' mới, đối tượng mà bạn đã tạo vẫn sẽ tham khảo nguyên gốc. Nó không bao giờ thay đổi. –

+0

Tôi nghĩ rằng cuối cùng tôi cũng nhận được nó. Một phần của sự nhầm lẫn của tôi là tôi đã mong đợi các công cụ web của tôi trong chrome để hiển thị nguyên mẫu của đối tượng mà tôi đã tạo. Tôi cũng nghĩ cho một số lý do ngớ ngẩn rằng việc sử dụng từ khóa mới cho phép bạn sử dụng từ khóa nguyên mẫu (ví dụ: f.prototype trong ví dụ của bạn), điều này không đúng. Khi tôi đã làm ví dụ Foo của bạn và thêm một chức năng để nguyên mẫu của nó, chức năng đó cũng xuất hiện trong đối tượng __proto__ khi tôi console.log (f). Vì vậy, về cơ bản __proto__ trong trường hợp này cho thấy chuỗi nguyên mẫu thường bị ẩn và khi bạn nói vĩnh viễn. – nahelm

0

Thuộc tính __proto__ của một thể hiện phải giống như thuộc tính của hàm tạoprototype thuộc tính.

Khi một đối tượng được tạo ra, sở hữu __proto__ của nó được thiết lập để tham khảo các đối tượng tương tự như nội [[Prototype]] (ví dụ: đối tượng constructor của nó của prototype) của nó. Gán giá trị mới cho __proto__ cũng thay đổi giá trị của thuộc tính nội bộ [[Prototype]], ngoại trừ đối tượng không thể mở rộng.

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

+0

Trong trường hợp này, vì đối tượng gốc là một đối tượng, nguyên mẫu của hàm tạo là đối tượng. Kết quả là 'constructor.prototype! = __proto__'. –

0

Object.create() đặt nguyên mẫu cho rằng trường hợp đối tượng cụ thể. prototype là thuộc tính trên hàm hàm dựng là đối tượng được tự động gán làm [[Prototype]] cho mỗi cá thể được tạo bằng cách sử dụng toán tử new với hàm tạo hàm đó.

__proto__ là cách không chuẩn để truy cập [[Prototype]] cho một trường hợp cụ thể. Bạn cũng có thể gọi Object.getPrototypeOf(this) cho một cách tiêu chuẩn để truy cập nguyên mẫu.

+1

Có thể muốn thay đổi "nguyên mẫu" thành '[[Prototype]]' để làm rõ khi bạn đang nói về tài sản nội bộ. –

+0

@MattBall cảm ơn! – Brandon

Các vấn đề liên quan