为什么即使在将原型重新分配给空对象之后,实例化对象仍然具有原型的属性?

时间:2018-05-26 08:37:46

标签: javascript

function Rabbit() {}
Rabbit.prototype = {
  eats: true
};

let rabbit = new Rabbit();

Rabbit.prototype = {};

alert( rabbit.eats ); // ?
为什么当我们设置它的引用时,rabbit.eat显示为true,即构造函数函数原型Rabbit为空?

我知道当编译器读取语句(rabbit.eat)时,它首先在对象中检查属性是否存在然后它在rabbit.__proto__中查找属性的Rabbit.prototype。但是在这里我们分配Rabbit.prototype = {}那么为什么对象兔子仍然有吃财产?

2 个答案:

答案 0 :(得分:2)

实例化Rabbit的原型,rabbit仍然是原始Rabbit.prototype对象,其eats: true。重新分配原型并不意味着解释器遍历每个实例化对象并更改原型。

如果您想更改现有对象的原型,可以使用setPrototypeOf,如下所示:

function Rabbit() {}
Rabbit.prototype = {
  eats: true
};
let rabbit = new Rabbit();
Rabbit.prototype = {};
Object.setPrototypeOf(rabbit, Rabbit.prototype);
alert(rabbit.eats); // ?

可是:

  

警告:根据现代JavaScript引擎如何在每个浏览器和JavaScript引擎中优化属性访问,非常慢的操作,改变对象的[[Prototype]]。改变继承对性能的影响是微妙和遥远的,并不仅仅局限于在Object.setPrototypeOf(...)语句中花费的时间,而是可以扩展到任何可以访问[[Prototype]的任何对象的代码。 ]]已被改变。如果您关心性能,则应避免设置对象的[[Prototype]]。而是使用Object.create()创建一个具有所需[[Prototype]]的新对象。

或者,代替重新分配原型,您可以将原型变成空对象:

function Rabbit() {}
Rabbit.prototype = {
  eats: true
};
let rabbit = new Rabbit();

// `for..in` will iterate over all properties, including inherited ones
// if you don't want that, iterate over Object.keys instead
for (const key in Rabbit.prototype) {
  delete Rabbit.prototype[key];
}

console.log(rabbit.eats);

其他突变rabbit的原始原型也将改变您在 rabbit 上可以访问的内容,只要您不是重新分配类的原型(创建一个单独的未链接对象):

function Rabbit() {}
Rabbit.prototype = {
  eats: true
};
let rabbit = new Rabbit();
// mutation, not reassignment
Rabbit.prototype.eats = 'foo';

console.log(rabbit.eats); // ?

答案 1 :(得分:0)

function Rabbit() {}
Rabbit.prototype = {
  eats: true
};

let rabbit = new Rabbit();

Rabbit.prototype = {};

alert( rabbit.eats );

let rabbit2 = new Rabbit();

alert(rabbit2.eats); //This will now say undefined

您没有更改已经实例化的对象的原型。