【问题标题】:Javascript and function prototype assignmentJavascript 和函数原型赋值
【发布时间】:2011-10-03 05:04:36
【问题描述】:

我一直假设函数的原型在所有对象之间共享,在某种意义上是通过引用。因此,如果您更改原型的某个属性的值,则共享该原型的所有对象的值也会随之更改。因此,例如在下面,似乎属性栏不是在所有对象之间共享,而是被复制。这是正确的吗?构造函数原型的属性是在创建时简单地复制到所有类对象中,还是通过链接共享?

function foo()
{
     this.bar = 1;
}
function derived() { }
derived.prototype = new foo()

object1 = new derived()
object2 = new derived()

object1.bar = 2;
//but notice if I had said here derived.prototype.bar = 3, object1.bar would still equal 2 but object2.bar would equal 3
alert(object2.bar) // this prints 1;

【问题讨论】:

    标签: javascript prototype-programming


    【解决方案1】:

    当您分配object1.bar = 2 时,您在object1 上创建了一个自己的属性,该属性只存在于该对象实例中,与它的原型无关。

    object1 上的此属性将隐藏derived.prototype 上存在的值,这意味着当您查找object1.bar 时,它将找到直接存在于该对象上的值。

    另一方面,如果你查找object2.bar,这个对象没有自己的bar 属性,所以属性查找将搜索这个继承自(derived.prototype)的对象,它会找到值1

    您的对象结构如下所示:

    对象1 -------- |酒吧:2 | ----------------- -------- |派生原型 | ---------- |------> |酒吧:1 | -- foo.prototype object2(没有自己的属性)| ---------- | ------------------ -------- | -> |构造函数: foo | | | ----------------- ------------------ -------- | v ------------------ | Object.prototype | ------------------ | v 空值

    ---> 行表示表示继承的内部[[Prototype]] 链接。

    【讨论】:

    • ohhh,很有道理,所以只要我不重新分配它,它就是指继承的属性,所以一旦我分配它就成为自己的属性?
    • 我现在明白了,那个图表很有帮助,非常感谢,你的回答很棒:-)
    • @rubixibuc,对,一旦你分配它,它将成为一个自己的属性,它会隐藏原型链中的任何值。另请注意,一旦创建对象,[[Prototype]] 链接就无法更改,例如,在创建 object1object2 之后,您将不同的对象重新分配给 derived.prototype 这不会影响这两个继承的属性对象。
    • @rubixibuc 我更新了图表,我忘记了foo.prototype :)
    【解决方案2】:

    例如,你有代码:

    function Animal() {
    }
    Animal.prototype.name="animal";
    
    function Dog() {
    }
    Dog.prototype = new Animal
    Dog.prototype.constructor=Dog;
    Dog.prototype.name="dog";
    
    object1 = new Animal();
    object2 = new Dog();
    

    因此,您有两个对象实例,看起来像(例如,您可以在 Chrome devtools 或 FF firebug 或...中进行检查):

    object1:
      __proto__: (is ref into an Animal.prototype object)
        constructor: function Animal()
        name: "animal"
        __proto__: Object (is ref into an Object.prototype object)
    
    object2:
      __proto__: (is ref into an Dog.prototype object)
        constructor: function Dog()
        name: "dog"
        __proto__: (is ref into an Animal.prototype object)
          constructor: function Animal()
          name: "animal"
          __proto__: (is ref into an Object.prototype object)
    

    当你运行下一个代码时(例如):

    alert(object1.name); // displayed "animal"
    alert(object2.name); // displayed "dog"
    

    发生了什么? 1) Javascript 在对象实例中查找属性名称(在object1object2 中)。 2) 找不到时,在对象实例的proto属性中查找(与类函数的原型相同)。 3)当没有找到时,它在 protoproto 和 next 和 next 中查找,而未找到 name 属性和其他 proto 找到。如果作为搜索属性的结果找到,则返回值,如果没有找到,则返回undefined

    如果你执行下一个代码会发生什么:

    object2.name = "doggy";
    

    结果你有object2:

    object2:
      name: "doggy"
      __proto__: (is ref into an Dog.prototype object)
        constructor: function Dog()
        name: "dog"
        __proto__: (is ref into an Animal.prototype object)
          constructor: function Animal()
          name: "animal"
          __proto__: (is ref into an Object.prototype object)
    

    属性直接赋值给实例对象,但原型对象保持不变。当你执行时:

    alert(object1.name); // displayed "animal"
    alert(object2.name); // displayed "doggy"
    

    当您需要创建|更改类的 shared 属性时,可以使用以下算法中的一个: 1)

    Animal.prototype.secondName="aaa";
    alert(object1.secondName); // displayed "aaa"
    alert(object2.secondName); // displayed "aaa"
    Animal.prototype.secondName="bbb";
    alert(object1.secondName); // displayed "bbb"
    alert(object2.secondName); // displayed "bbb"
    // but
    Animal.prototype.secondName="ccc";
    object1.secondName="ddd";
    alert(object1.secondName); // displayed "ccc"
    alert(object2.secondName); // displayed "ddd"
    

    2) 在函数类原型中创建object类型的属性,并为该对象的属性赋值。

    Animal.prototype.propObject={thirdName:"zzz"};
    alert(object1.propObject.thirdName); // displayed "zzz"
    alert(object2.propObject.thirdName); // displayed "zzz"
    Animal.prototype.propObject.thirdName="yyy";
    alert(object1.propObject.thirdName); // displayed "yyy"
    alert(object2.propObject.thirdName); // displayed "yyy"
    object1.propObject.thirdName="xxx";
    alert(object1.propObject.thirdName); // displayed "xxx"
    alert(object2.propObject.thirdName); // displayed "xxx"
    object2.propObject.thirdName="www";
    alert(object1.propObject.thirdName); // displayed "www"
    alert(object2.propObject.thirdName); // displayed "www"
    

    【讨论】:

    • 解释得很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-21
    • 2011-01-20
    • 2011-10-18
    • 2016-09-19
    • 1970-01-01
    • 2018-05-25
    相关资源
    最近更新 更多