代码之家  ›  专栏  ›  技术社区  ›  Bjorn

如果原型的属性不是由实例本身设置的,为什么在原型更新时要更新实例的属性?

  •  3
  • Bjorn  · 技术社区  · 14 年前

    如果一个实例的属性不是由实例本身设置的,那么为什么当原型更新时,存储原语值而不是引用的实例的属性会更新?

    var Obj = function () {};
    Obj.prototype.num = 1;
    
    var myObj = new Obj();
    var myOtherObj = new Obj();
    console.log(myObj.num); //logs 1
    console.log(myOtherObj.num); //logs 1
    
    //After instances are created they still share the value (which is strange):
    Obj.prototype.num = 3;
    console.log(myObj.num); //logs 3
    console.log(myOtherObj.num); //logs 3
    
    //Update one of the instances property
    myObj.num += 2;
    console.log(myObj.num); //logs 5
    console.log(myOtherObj.num); //logs 3
    
    //Here it gets weird:
    Obj.prototype.num = 4;
    console.log(myObj.num); //logs 5 not updated
    console.log(myOtherObj.num); //logs 4 updated
    

    这里有一些奇怪的事情:

    创建实例后,更新类定义将更新实例值,前提是且仅当实例本身从未更新实例值。

    如果我试图将其推理出来,那么最初的实例似乎没有自己的实例 num this.num 或与外部 instanceName.num )在实例上创建属性。

    这似乎与ECMA5规范所说的不符:

    prototype属性的值用于在将函数对象作为新创建对象的构造函数调用之前初始化新创建对象的[[prototype]]内部属性。

    3 回复  |  直到 10 年前
        1
  •  4
  •   Mark Bessey    14 年前

    其工作方式是首先在对象上查找属性,然后如果找不到属性,则在原型中查找它们。

    似乎是最初的例子 没有自己的num属性,并且 查找发生在发现它的地方 实际设置属性(内部 使用this.num或外部使用 实例的属性。实例的属性。

    这就是它的工作原理。如果要删除在对象上设置的属性,可以使用“删除”:

    delete myOtherObj.num;
    

    这将删除myOtherObj的num属性,并允许原型版本显示出来。

    您引用的规范部分试图解释如何为新创建的实例设置内部[[Prototype]]属性。除了在属性查找中的角色外,[[Prototype]]与任何其他Javascript对象引用都类似。


    另一个例子是:

    function Obj() {};
    Obj.prototype.num=1;
    
    var myObj = new Obj();
    console.log(myObj.num); // logs 1
    
    Obj.prototype = {num:3}; // replaces Obj.prototype
    console.log(myObj.num); // logs 1
    
    var myOtherObj = new Obj(); 
    console.log(myOtherObj.num); // logs 3
    console.log(myObj.num); // still logs 1
    

    注意,一旦对象被构造,它就保持对任何被设置为构造函数原型的对象的引用 . 更改该对象的属性仍将影响对同一原型的任何其他引用。

        2
  •  3
  •   Marcel Korpel    14 年前

    当你试图访问一个对象的属性时,这个属性不是在这个对象中设置的,JS引擎会启动原型链并尝试在那里读取它。只要未在该对象中显式设置属性,则为真。

    仅当设置对象的某个属性时,该属性才在该对象中定义。这也是更改对象原型时,已声明对象的特定属性更改的原因。

    Obj.prototype.num = 3;
    console.log(myObj.num); //logs 3
    console.log(myOtherObj.num); //logs 3
    

    在这里你还可以读到 Obj.prototype.num .

    myObj.num += 2;
    

    你真的来了 阅读 对象原型.num myObj.num

    Obj.prototype.num = 4;
    console.log(myObj.num); //logs 5 not updated
    console.log(myOtherObj.num); //logs 4 updated
    

    现在你读 肌瘤 对象原型.num ,分别是。

        3
  •  2
  •   user113716    14 年前

    其他人会比我更好地解释这一点,所以同样的用户,可以自由地评论我的答案。我会删除,如果它是非常恶劣的。


    num 属性,它将查找其原型(或父级或父级或父级或父级或其他)的值。

    所以无论这个价值是什么,都是你将得到的价值。更新它,任何查看它的对象都会找到更新后的值。


    编辑:

    4.3.4条

    构造器

    创建和初始化对象的函数对象。 注意constructors prototype属性的值是一个prototype对象,用于实现继承和共享属性。

    原型

    为其他对象提供共享属性的对象。

    注意,当构造函数创建对象时,该对象隐式引用构造函数原型属性以解析属性引用。constructors prototype属性可以被程序表达式constructor.prototype引用,并且添加到对象原型的属性通过继承被共享原型的所有对象共享。或者,可以使用object.create内置函数使用显式指定的原型创建新对象。