JavaScript原型继承
这看起来不一致,但可能是由于我是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);
原型的东西是,你可以从它们整天读取,而且它不会改变指向什么的底层结构。 但是,第一次执行任务时,您将替换该属性指向的内容。
在你的情况下,你实际上并没有重新分配原型属性,而是修改了在该属性中找到的基础结构的值。
这意味着共享A原型的所有对象实际上共享A的实现。这意味着A中携带的任何状态都可以在B的所有实例上找到。当您在B实例上对该属性进行赋值时,你已经有效地取代了那个实例(只有那个实例)指向的内容(我相信这是由于B上有一个新的属性“name”,它在范围链中被命中,在到达“name”之前,在A上实施)。
编辑:
给出一个更直观的例子:
B.prototype = new A();
var obj1 = new B();
现在,我们第一次阅读时,这个解释器就是这样做的:
obj1.name;
解释者:“我需要属性名称,首先,检查B. B没有'名称',所以让我们继续沿着范围链继续下一步,A. Aha!A有'name',返回”
但是,当您执行写操作时,解释器实际上并不关心继承的属性。
obj1.name = "Fred";
解释者:“我需要分配属性'名',我在B的这个实例的范围内,所以给'B'分配'Fred',但是我把所有其他东西放在范围链中(即A)”
现在,下次你阅读...
obj1.name;
解释器:“我需要属性'name',Aha!这个B的实例已经拥有属性'name',只需返回 - 我不关心作用域链的其余部分(即A.name)”
所以,第一次写名字时,它将它作为实例的第一类属性插入,并且不再关心AAname上的内容,它只是在作用域链的更远处,而JS解释器不会在它发现它所寻找的东西之前没有那么远。
如果“名称”在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
现在,就你的数组而言,你从来没有用一个新的数组实际替换范围链上的列表。 你所做的是在数组本身上抓取一个句柄,并为其添加一个元素。 因此,B的所有实例都受到影响。
解释器:“我需要得到'list'propery,然后添加一个元素,检查这个B ... nope的实例,没有'list'属性,接下来在范围链中:A.Yep,A有'列表',使用它。现在,推入该列表“
如果你这样做,情况就不会如此:
obj1.list = [];
obj1.push(123);
您更改了A中引用的列表的值,但未更改引用本身。 obj2.name应该是“A”。
当然,我宁愿任何后续的子类实例都不会从其他实例获取值,但如果发生这种情况,它应该是一致的!
那么不要从A
的新实例继承,从A
的原型继承。 这将确保你不会继承状态,你只能继承行为。 这是原型继承的棘手部分,它也继承了状态,不仅像传统的OOP继承一样行为。 在JavaScript中,构造函数只能用于设置实例的状态。
var A = function (list) {
this.list = list;
this.name = "A";
};
A.prototype.getName = function () {
return this.name;
};
var B = function (list) {
this.list = list;
this.name = "B";
};
B.prototype = A.prototype; // Inherit from A's prototype
B.prototype.constructor = B; // Restore constructor object
var b = new B([1, 2, 3]);
// getName() is inherited from A's prototype
print(b.getName()); // B
顺便说一句,如果你想改变A中的某些东西,通过B,你必须这样做:
B.prototype.name = "obj1";
链接地址: http://www.djcxy.com/p/30053.html