2013-06-27 41 views
5

Nhà điều hành instanceof nên xem xét nguyên mẫu, phải không? Tại sao nó không thay đổi câu trả lời của nó sau khi nguyên mẫu của đối tượng đã được thay đổi? Ví dụ dưới đây:tại sao instanceof tiếp tục nói đúng sau khi nguyên mẫu thay đổi?

// The .prototype of objects created with 'new MyKlass' 
// is MyKlass.prototype 
var MyKlass = function(name, age) { 
    this.name = name; 
    this.age = age; 
} 

var xx = new MyKlass('xx', 20); 
console.log(xx instanceof MyKlass);  // true, OK 

xx.prototype = new String('s'); 
console.log(xx instanceof MyKlass);  // also true, WHY??? 

Trả lời

9

trường hợp này là giải thích in the MDN:

Lưu ý rằng nếu giá trị của một bài kiểm tra instanceof có thể thay đổi dựa trên thay đổi thuộc tính prototype của nhà thầu, nó không thể được thay đổi bằng cách thay đổi một nguyên mẫu đối tượng, bởi vì việc thay đổi một đối tượng mẫu là không thể trong ECMAScript chuẩn. Tuy nhiên nó là có thể sử dụng phi tiêu chuẩn __proto__ giả sở hữu

này sẽ đăng nhập sai:

xx.constructor.prototype = new String('s'); 
console.log(xx instanceof MyKlass); 

Tóm lại, bạn không nên cố gắng đột biến đối tượng JavaScript, họ đã không được thiết kế để có thể thay đổi. Tôi không biết trường hợp sử dụng của bạn là gì nhưng có lẽ đó là giải pháp tốt hơn, có thể là thành phần, trạng thái nội bộ hay thứ gì đó khác.

+0

Tại sao có thể 'prototype' của 'MyKlass' thay đổi nhưng không phải 'xx.prototype'? Arent cả hai 'MyKlass' và' xx' đối tượng? – zpzp

+0

bạn có ý gì khi tắt tiếng? bạn có thể giải thích rõ hơn một chút không? –

+0

@OliverWatkins Biến đổi một đối tượng là hoạt động chung của việc thay đổi lớp của nó. Hầu hết các ngôn ngữ OOP (hoặc POOP) không cho phép bạn làm điều đó bởi vì nó lộn xộn. –

3

Nó không nhìn vào .prototype nhưng [[Prototype]], hoặc những gì có sẵn trong một số trình duyệt như .__proto__

xx.__proto__ = new String("s"); 
console.log(xx instanceof MyKlass); 
//false 
console.log(xx instanceof String); 
//true 

Gán thuộc tính .prototype để một hàm phi không có tác dụng trừ sự phân công bình thường của bất kỳ tài sản bình thường thực sự. Và đối với các chức năng chỉ có tác dụng khi chức năng được sử dụng trong instanceof kiểm tra hoặc gọi với new.

+0

thiết lập '__proto__' có song song tiêu chuẩn ECMAScript (có thể trong ES 5)? – zpzp

+0

@zpzp không, nhưng có vẻ như nó sẽ có sẵn trong ES6 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto – Esailija

3

Toán tử instanceof sẽ xem xét nguyên mẫu, phải không?

Vâng, đúng vậy. Xem MDN docs.

Tại sao nó không thay đổi câu trả lời sau khi nguyên mẫu của đối tượng đã được thay đổi?

var xx = new MyKlass('xx', 20); 
xx.prototype = new String('s'); 

Bởi vì bạn không thay đổi nguyên mẫu của đối tượng xx của bạn, nhưng cho nó một tài sản prototype. Object.getPrototypeOf(xx) === MyKlass.prototype vẫn áp dụng. Xem __proto__ VS. prototype in JavaScript để biết chi tiết. Điều gì sẽ làm việc:

MyKlass.prototype = {}; // overwrite with a different object 
console.log(xx instanceof MyKlass); // false now, xx doesn't inherit from the {} 

hoặc

xx.__proto__ = String.prototype; // or something 
console.log(xx instanceof MyKlass); // false now, xx doesn't inherit from MyKlass.prototype 

ý rằng văn bản cho nội bộ [[Prototype]] qua __proto__ là phi tiêu chuẩn trong ES5

+0

Vì vậy, thuộc tính '.prototype' của chức năng là đặc biệt trong một cách, bởi vì thiết lập nó có ý nghĩa ngoài việc chỉ cần thiết lập các tài sản? – zpzp

+0

Có, nó đề cập đến đối tượng mà các cá thể hoặc được thiết lập để kế thừa từ khi hàm [được gọi là hàm tạo với 'new'] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/ Tham khảo/Toán tử/mới) – Bergi