简体   繁体   English

原型上的属性受到不同的影响

[英]Properties on a prototype being affected differently

I'm using prototype inheritance in this code snippet: 我在这段代码片段中使用了原型继承:

 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 

I expect the output to be 我期待输出

"red,blue,green"
1

or 要么

"red,blue,green,black"
2

but I get: 但我得到:

"red,blue,green,black"
1

Why? 为什么?

The problem is here: 问题出在这里:

SubType.prototype = new SuperType();

Because the SuperType constructor puts the .colors Array on the object, and because the object is used as the .prototype of SubType , that .colors Array is shared between all SubType instances. 因为SuperType构造函数将.colors数组放在对象上,并且因为该对象用作SubType.prototype ,所以.colors Array在所有SubType实例之间共享。

Instead, don't invoke the constructor when setting up inheritance but do invoke it within the SubType constructor. 取而代之的是,建立继承时,不要调用构造函数,但不要在内部调用其SubType的构造。

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

The reason the .x didn't have the same issue is that numbers are not mutable, so when you try to modify it, a new x gets created directly on the object you're using instead of mutating the .prototype . .x没有相同问题的原因是数字不可变,所以当你尝试修改它时,会直接在你正在使用的对象上创建一个新的x而不是改变.prototype

When you write 当你写作

instance1.x = 2;

you are adding a new property called x to instance1 . 您正在向instance1添加一个名为x的新属性。

The prototype of instance1 , which you can look up with instance1.__proto__ , is unaffected. instance1的原型,你可以使用instance1.__proto__ ,不受影响。 The value of instance1.__proto__.x is still 1. instance1.__proto__.x值仍为1。

When you refer to 当你提到

instance1.x

the object's own property instance1.x takes precedence over the prototype's property instance1.__proto__.x . 对象自己的属性instance1.x优先于原型的属性instance1.__proto__.x We say that the x on instance1 shadows the x on instance1.__proto__ . 我们说xinstance1 阴影xinstance1.__proto__

When JavaScript evaluates instance1.x , it checks the own properties of instance1 before moving up the prototype chain. 当JavaScript的评估instance1.x ,它检查的自己的属性instance1连升原型链之前。 Therefore, the value of the own property instance1.x is what you see. 因此,您看到的属性instance1.x的值。

But when you write 但是当你写作

instance1.colors

the object instance1 does not have an own property called colors . 对象instance1没有称为colors的属性。 Therefore, JavaScript looks at its prototype. 因此,JavaScript会查看其原型。 It finds instance1.__proto__.colors and returns its current value. 它找到instance1.__proto__.colors并返回其当前值。

When you wrote 你写的时候

instance1.colors.push("black");

you did not add a new property to instance1 . 您没有向instance1添加新属性。 You merely modified the array instance1.__proto__.colors . 你只是修改了数组instance1.__proto__.colors All objects that have the same prototype will see the same value of colors unless they have a property that shadows colors . 具有相同原型的所有对象将看到相同的colors值,除非它们具有阴影colors的属性。

In the code snippet below, I have made a third object, c , that defines an own property called colors , which shadows the prototype's property c.__proto__.colors . 在下面的代码片段中,我创建了第三个对象c ,它定义了一个名为colors的属性,它隐藏了原型的属性c.__proto__.colors

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

The value of the own property c.colors is a different array than the prototype's property c.__proto__.colors . 自己的属性c.colors的值是与原型的属性c.__proto__.colors不同的数组。 Objects that don't have an own property colors will continue to see the value of the prototype's 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"); ax = 2; message('a.colors: ' + a.colors.join(', ')); // red, blue, green, black (prototype's colors) message('ax: ' + ax); // 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('bx: ' + bx); // 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; } 
 <div id="messageBox"></div> 

When you run .push("black") you are using a method that modifies the object (the list of colours) in place; 当您运行.push("black")您正在使用一种方法来修改对象(颜色列表); so all variables pointing at that object see the change. 所以指向该对象的所有变量都会看到变化。

When you use = 2 , you are replacing the value of that one variable, so other variables can still point at the original value. 当您使用= 2 ,您将替换该一个变量的值,因此其他变量仍然可以指向原始值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM