med*_*med 16 javascript inheritance prototype
这似乎不一致,但可能是因为我是javascript原型继承功能的新手.
基本上,我有两个基类属性,"列表"和"名称".我实例化两个子类并为属性赋值.当我实例化第二个子类时,它从第一个子类实例获取列表值,但仅用于"列表"而不用于"名称".这是怎么回事??当然,我希望任何后续的子类实例都不会从其他实例获取值,但如果这种情况发生,它应该是一致的!
这是一段代码:
function A()
{
this.list = [];
this.name = "A";
}
function B()
{
}
B.prototype = new A();
var obj1 = new B();
obj1.list.push("From obj1");
obj1.name = "obj1";
var obj2 = new B();
//output:
//Obj2 list has 1 items and name is A
//so, the name property of A did not get replicated, but the list did
alert("Obj2 list has " + obj2.list.length + " items and name is "+ obj2.name);
Run Code Online (Sandbox Code Playgroud)
Mat*_*att 13
原型的东西是,你可以整天读取它们,它不会改变指向什么的底层结构.但是,第一次执行赋值时,您将在该实例上替换该属性指向的内容.
在您的情况下,您实际上没有重新分配prototyped属性,您修改了在该属性中找到的底层结构的值.
这意味着共享A原型的所有对象实际上共享 A 的实现.这意味着A中携带的任何状态都将在B的所有实例上找到.在B的实例上对该属性进行赋值的那一刻,你已经有效地替换了那个实例(并且只有那个实例)指向的东西(我相信这是因为B上有一个新的属性"name",在它到达"name"之前在范围链中被命中在A)上实施.
编辑:
为了给出一个更明确的例子:
B.prototype = new A();
var obj1 = new B();
Run Code Online (Sandbox Code Playgroud)
现在,我们第一次进行读取时,解释器会执行以下操作:
obj1.name;
Run Code Online (Sandbox Code Playgroud)
口译员:"我需要属性名称.首先,检查B. B没有'名称',所以让我们继续沿着范围链.接下来,A.Aha!A有'名字',返回那个"
但是,当您执行写操作时,解释器实际上并不关心继承的属性.
obj1.name = "Fred";
Run Code Online (Sandbox Code Playgroud)
解释器:"我需要分配属性'name'.我在B 的这个实例的范围内,所以将'Fred'分配给B.但是我将其他所有内容都放在范围链的另一端(即A)"
现在,下次你做一个阅读...
obj1.name;
Run Code Online (Sandbox Code Playgroud)
翻译:"我需要属性'名称'.啊哈!这个B的实例已经将属性'name'放在它上面.只需返回 - 我不关心范围链的其余部分(即A.name)"
所以,你写的名字第一次时,它把它作为实例第一类属性,已经不关心什么是对AAname是仍然存在,它只是进一步下跌的作用域链,和JS解释没有按在找到它想要的东西之前,要走得那么远.
如果"name"在A中有一个默认值(就像你有的那样,那就是"A"),那么你会看到这种行为:
B.prototype = new A();
var obj1 = new B();
var obj2 = new B();
obj1.name = "Fred";
alert(obj1.name); // Alerts Fred
alert(obj2.name); // Alerts "A", your original value of A.name
Run Code Online (Sandbox Code Playgroud)
现在,就您的数组而言,您实际上从未使用新数组替换作用域链上的列表.你所做的就是抓住数组本身的一个句柄,并为它添加一个元素.因此,B的所有实例都受到影响.
解释:"我需要得到'列表’属性格式,和元素添加进去检查B的这种情况下......不,没有一个'清单’属性然后在作用域链:A.是的,A有'列表',使用它.现在,按下列表"
如果您这样做,情况就不是这样了:
obj1.list = [];
obj1.push(123);
Run Code Online (Sandbox Code Playgroud)
您更改了 A 中引用的列表的值,但未更改引用本身。obj2.name 应该是“A”。