2011-07-30 31 views
10

Ai đó có thể giải thích cho tôi về việc sử dụng Me.prototype.constructor = Me; và tại sao cần thiết, khi mã này đang hoạt động và không có mã?Sử dụng hàm tạo nguyên mẫu trong JS

Trong đối tượng mẫu mã được tạo trên đối tượng Me và nó được khởi tạo và thay thế đối tượng nguyên mẫu cũ. Tại sao tôi cần trỏ đến hàm tạo Me trong một mã đã cho?

function Me(){ 
    this.name = 'Dejan'; 

} 

function You(){ 
    this.name = 'Ivan'; 
} 

Me.prototype = new You(); 

somebody = new Me(); 

Me.prototype.constructor = Me; // Why? 

Me.prototype.foo = function(){ 
    alert('Proto Me!'); // It always fire up this alert, ether constructor is pointing to Me or not... ! 
} 

You.prototype.foo = function(){ 
    alert('Proto You!'); 
} 

somebody.foo(); 
alert(somebody.name); // Alert 'Dejan' 
+0

Tôi tin rằng các trình duyệt kế thừa kiểm tra thuộc tính '.constructor' cho từ khóa' instanceof'. – Raynos

+0

Đây là một cuốn sách từ năm 2006. –

Trả lời

11

Nó không cần thiết, và nó thậm chí còn không cần thiết cho instanceof trái với niềm tin phổ biến (instanceof nội bộ kiểm tra chuỗi nguyên mẫu và không cần một tài sản constructor). Thông thường, constructor vốn vốn là thuộc tính không thể đếm được trên số prototype của hàm tạo. Vì vậy, cho bất kỳ đối tượng nào được khởi tạo bởi hàm tạo đó, một thuộc tính không thể liệt kê constructor, trỏ đến hàm tạo đó.

Bạn nên đặt nó ở đó nếu bạn cần, lý tưởng là không thể đếm được. Một số mã sẽ giả sử sự tồn tại của .constructor trên các đối tượng.

Trong mã bạn đã đăng, có, khi thực hiện kế thừa theo cách đó, cần phải đặt lại hàm tạo (nếu bạn muốn), vì đối tượng bạn đã khởi tạo để làm nguyên mẫu con có thuộc tính hàm tạo trỏ đến sai constructor (constructor của nó).

Trong ES5, bạn sẽ làm gì:

Child.prototype = Object.create(Parent.prototype, { 
    constructor: { value: Child, enumerable: false } 
}); 

chỉnh sửa: Ngoài ra, có thể là đáng nói, khi thực hiện thừa kế bằng cách sử dụng phi tiêu chuẩn __proto__, nó không phải là cần thiết để thiết lập lại constructor vì __proto__ chỉ định và nguyên mẫu của đối tượng , mà nó nói, đối tượng mà trên đó tra cứu sẽ được thực hiện khi một tài sản riêng không tồn tại. Một prototype mới sẽ luôn có một thuộc tính được gọi là constructor.

Vì vậy, trong thực hiện:

var child = function() {}; 
child.prototype.__proto__ = parent.prototype; 

Bạn không cần phải thiết lập constructor vì tài sản nhà xây dựng cơ sở child.prototype vẫn còn đó. Nếu được truy cập, không cần tìm kiếm chuỗi mẫu thử nghiệm.

+2

Bạn có chắc IE6 không kiểm tra thuộc tính 'constructor'? Và 'Object.create' đặt thuộc tính' constructor' cho bạn. Bạn không cần phải làm điều đó bằng tay – Raynos

+4

Raynos, Không, tôi không chắc chắn về IE6, vì tôi không thực sự quan tâm đến IE6. Ngoài ra, Object.create không thiết lập hàm tạo cho bạn, nó không có khái niệm về một hàm tạo, trên thực tế, đó là điểm của Object.create. Bạn sẽ chỉ nhận được một thuộc tính constructor bằng hàm tạo của cha, điều này sẽ sai đối với thừa kế. Vì vậy, bạn cần phải thay đổi nó. – chjj

+1

quyền của bạn xấu về 'hàm tạo'. Object.create không có khái niệm về hàm tạo – Raynos

5

Nếu bạn thay thế dòng

Me.prototype.constructor = Me; // Why? 

với

console.log(Me.prototype.constructor); 
Me.prototype.constructor = Me; // Why? 

bạn sẽ thấy rằng trước khi đặt nó, Me.prototype.constructorYou, vì Me.prototype là một thể hiện của You do dòng

Me.prototype = new You(); 

Vì vậy, dòng thứ e // Why? nhận xét là cần thiết để "sửa" ấn tượng nhầm lẫn này mà bạn đã đưa ra JavaScript bằng cách thực hiện kế thừa theo cách này.


Về cơ bản vấn đề xuất hiện vì bạn đang cố gắng sử dụng thừa kế nguyên mẫu để thực hiện kế thừa cổ điển. Prototypal kế thừa hoạt động trên các cá thể đối tượng, và không có khái niệm về "lớp" hoặc thậm chí, thực sự, "loại", nhưng JavaScript làm cho mọi thứ thêm khó hiểu với toàn bộ new, .constructorinstanceof doanh nghiệp.

Một cách cụ kỵ hơn để làm điều này là điều mà là để tránh né nhà xây dựng có lợi cho các nhà xây dựng điện, tức là chức năng mà trả về một đối tượng với các hình thức mà bạn mong muốn:

function begetPart(partNumber, description) { 
    return Object.create({}, { 
     number: { value: partNumber }, 
     description: { value: description }, 
     describe: { 
      value: function() { 
       alert(this.description); 
      } 
     } 
    }); 
} 

function begetTire(partNumber, speed) { 
    return Object.create(
     begetPart(partNumber, "A tire"), 
     { 
      speed: { value: speed }, 
      describe: { 
       value: function() { 
        alert(this.description + "; speed = " + this.speed); 
       } 
      } 
     } 
    ); 
} 

var genericPart = begetPart(1234, "A widget"); 
genericPart.describe(); // alerts "A widget" 

var tire = begetTire(4567, "fast"); 
tire.describe(); // alerts "A tire; speed = fast" 

Ở đây chúng ta sử dụng Object.create để nói " tạo một cá thể đối tượng dựa trên cá thể đối tượng khác này ". Ví dụ khác là một đối tượng trống, mới cho begetPart và một "phần thể hiện" mới với một số thuộc tính được điền sẵn cho begetTire. Điều này phản ánh tốt hơn cách JavaScript và sự thừa kế nguyên mẫu thực sự hoạt động, vì trong các cá thể đối tượng thừa kế prototy kế thừa từ các cá thể đối tượng khác, mà không có toàn bộ ý tưởng "kiểu" hoặc "lớp" này cản trở.

+0

'hàm Object() {[native code]}' – towry

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