为什么在JS中你不能在原型上设置非函数

时间:2015-12-11 20:39:54

标签: javascript prototypal-inheritance

我不确定如何标题,但这里有一个例子让我惹恼了我

myLib.prototype._handlers = {};
myLib.prototype.destroy = function () {
  this._handlers = {};
}

我正在写测试,幸运的是它抓住了这个问题。破坏方法实际上并不起作用。

为什么会这样?我认为原型上的属性是为每个new myLib实例创建的,但是通过编写这些测试所有 new myLib实例都有这些处理程序。

2 个答案:

答案 0 :(得分:5)

您可以在原型上设置非功能。问题是原型上的属性是在对象的所有实例之间共享的。这通常不是您想要的数据属性,但它是您想要的函数属性。

因此,相反,您通常会在对象的构造函数中初始化数据属性,这使得它们自己拥有"每个实例都有唯一的属性,通常是你想要的。

  

我认为原型上的属性是为每个创建的   新的myLib实例,但从编写这些测试所有新的myLib   实例有这些处理程序。

原型是一个对象,用作属性的查找机制。当您引用var x = obj.prop时,Javascript首先查看obj对象本身,以查看是否存在名为"prop"的属性。如果有,那被认为是"拥有"属性和它的值被提取。如果没有,那么它转到原型对象,看它是否有一个"拥有"名为"prop"的属性。如果是,则返回该值。如果它没有那个命名属性,那么它会检查原型对象是否有自己的原型,如果有,它会检查一个,依此类推......

因此,原型充当查找参考。没有复制或创建任何新内容。这只是一个"参考"到可用于查找的原型。这就是原型在所有实例之间共享的原因。出于多种原因,它是故意设计的。一个原因是它的存储效率很高。所有实例共享的原型对象只有一个,因此所有这些引用都不必在每个对象实例上重复。

使用以下内容分配属性时

obj.someProp = "foo";

它只会影响"拥有"属性。它不会影响原型。如果有一个"拥有"在名为"someProp"的对象上的属性,然后更新它的值。如果没有,那么一个新的"拥有"在实际对象实例上创建属性。如果原型上有这个名称的属性,那么该值现在基本上是隐藏的,因为Javascript属性查找方案将找到" own"属性优先,并将从那时起使用(只要它存在)。

了解在.destroy()方法中分配属性时可能也很重要,例如:

myLib.prototype._handlers = {};
myLib.prototype.destroy = function () {
  this._handlers = {};
}  

执行myLib.prototype._handlers方法时,实际上并没有触及obj.destroy()值。相反,this._handlers = {};在对象的实际实例上创建一个新属性,一个"拥有"属性。对this._handlers的任何引用都会找到"拥有"首先是财产,从那时起将会使用什么,所以它可能会出现#34;喜欢它改变了原型价值,但新的"拥有"属性只是掩盖了原型值。

答案 1 :(得分:1)

  

我认为原型上的属性是为每个新的myLib实例创建的新属性

没有。原型不会创建任何东西。原型继承是一种级联查找系统,其中对象上的属性的查找可以升级为原型祖先。

每个对象都有继承的属性及其“自己的”属性。实际上只有“自己的”属性直接存在。原型值不直接存在于实例上,而是当您在对象上请求某个属性名称时访问它们,并且该属性不作为自己的属性存在。

设置属性值始终直接在对象上设置自己的属性。因此,this._handlers = {}直接在您调用_handlers方法的实例上设置(并可能创建)destroy属性。虽然属性 access 会对原型链进行级联以查找具有正确名称的属性,但设置属性这样做。

理解this值在函数调用时动态设置也很重要,并且可能因调用而异。也就是说,即使instance1.destroy()函数与完全相同的函数对象,调用instance2.destroy()this也会有不同的destroy值。如果您明确呼叫thismyLib.prototypemyLib.prototype.destroy()的唯一情况就是{。}}。