【问题标题】:Properties on a prototype being affected differently原型上的属性受到不同的影响
【发布时间】:2015-12-27 23:42:01
【问题描述】:

我在这段代码 sn-p 中使用原型继承:

function SuperType() {
  this.colors = ["red", "blue", "green"];
  this.x = 1;
}

function SubType() {}
SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.colors.push("black");
instance1.x = 2;
//alert(instance1.colors); // "red,blue,green,black"
//alert(instance1.x); // 2

var instance2 = new SubType();
alert(instance2.colors); // "red,blue,green,black"
alert(instance2.x); // 1

我希望输出是

"red,blue,green"
1

"red,blue,green,black"
2

但我明白了:

"red,blue,green,black"
1

为什么?

【问题讨论】:

  • 您刚刚创建了SubType 的新实例。试试var instance2 = instance1
  • 数组和对象通过引用传递,而对于原始类型(字符串、数字等),引用是值,related

标签: javascript inheritance prototype prototypal-inheritance prototype-programming


【解决方案1】:

问题出在这里:

SubType.prototype = new SuperType();

因为SuperType 构造函数将.colors 数组放在对象上,并且因为该对象用作SubType.prototype,所以.colors 数组在所有SubType 实例之间共享。

相反,在设置继承时不要调用构造函数,而是SubType构造函数中调用它。

function SubType() {
    SuperType.apply(this, arguments);
}
SubType.prototype = Object.create(SuperType.prototype);

.x 没有相同问题的原因是数字不可变,因此当您尝试修改它时,会直接在您正在使用的对象上创建一个新的 x,而不是改变.prototype.

【讨论】:

    【解决方案2】:

    当你写作时

    instance1.x = 2;
    

    您正在向instance1 添加一个名为x 的新属性。

    instance1 的原型,你可以用instance1.__proto__ 查找,不受影响。 instance1.__proto__.x 的值仍然是 1。

    当你提到

    instance1.x
    

    对象自己的属性instance1.x 优先于原型的属性instance1.__proto__.x。我们说instance1 上的x 阴影 instance1.__proto__ 上的x

    当 JavaScript 计算 instance1.x 时,它会在向上移动原型链之前检查 instance1 自己的属性。因此,自己的属性instance1.x的值就是你看到的。

    但是当你写的时候

    instance1.colors
    

    对象instance1 没有名为colors 的自己的属性。因此,JavaScript 着眼于它的原型。它找到instance1.__proto__.colors 并返回其当前值。

    你写的时候

    instance1.colors.push("black");
    

    您没有向instance1 添加新属性。您只是修改了数组instance1.__proto__.colors。所有具有相同原型的对象都将看到相同的 colors 值,除非它们具有遮蔽 colors 的属性。

    在下面的代码 sn-p 中,我创建了第三个对象 c,它定义了一个名为 colors 的自己的属性,它隐藏了原型的属性 c.__proto__.colors

    var c = new SubType();
    c.colors = [ 'orange', 'purple' ];
    

    自有属性c.colors 的值与原型属性c.__proto__.colors 的值不同。没有自己的属性colors 的对象将继续看到原型的colors 的值。

    function SuperType() {
        this.colors = ["red", "blue", "green"];
        this.x = 1;
    }
    function SubType() {}
    SubType.prototype = new SuperType();
    
    var a = new SubType();
    a.colors.push("black");
    a.x = 2;
    message('a.colors: ' + a.colors.join(', '));  // red, blue, green, black (prototype's colors)
    message('a.x: ' + a.x);                       // 2 (own property x)
    message('a.__proto__.x: ' + a.__proto__.x);   // 1 (prototype's x)
    
    var b = new SubType();
    message('b.colors: ' + b.colors.join(', '));  // red, blue, green, black (prototype's colors)
    message('b.x: ' + b.x);                       // 1 (prototype's x)
    
    var c = new SubType();
    // Make an own property, colors, that shadows the prototype's property.
    c.colors = [ 'orange', 'purple' ];
    message('c.colors: ' + c.colors.join(', '));  // orange, purple (own property colors)
    message('b.colors: ' + b.colors.join(', '));  // red, blue, green, black (prototype's colors)
    message('a.colors: ' + a.colors.join(', '));  // red, blue, green, black (prototype's colors)
    
    
    function message(line) {
      document.getElementById('messageBox').innerHTML += line + '<br>';
    }
    body {
      font-family: sans-serif;
    }
    &lt;div id="messageBox"&gt;&lt;/div&gt;

    【讨论】:

      【解决方案3】:

      当您运行.push("black") 时,您正在使用一种方法来修改对象(颜色列表);所以指向该对象的所有变量都会看到变化。

      当您使用= 2 时,您正在替换那个变量的值,因此其他变量仍然可以指向原始值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-08-04
        • 2012-05-21
        • 2018-12-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多