我在这里试图使用JavaScript中的继承,我发现在Parent类中继承了Child类的数组值的问题.下面的代码是正常继承:
var Parent = function() {
this.list = [];
};
var Child = function() {};
Child.prototype = new Parent;
Child.prototype.constructor = Child;
var obj1 = new Child;
obj1.list.push("hello");
console.log(obj1.list); // prints ["hello"];
Run Code Online (Sandbox Code Playgroud)
当我初始化新的子对象(继承父其中包含数组变量命名列表)来OBJ1,并试图推动obj1.list与价值"你好",obj1.list打印["你好"] ..到目前为止好.
问题是当我做上面的例子中,我试图初始化新的子对象OBJ2然后推OBJ2的名单有值'再见’,并obj2.list现在的打印效果['你好’,'再见’.(见下面的代码:)
var obj2 = new Child;
obj2.list.push("goodbye");
console.log(obj2.list); // prints ["hello", "goodbye"];
Run Code Online (Sandbox Code Playgroud)
我可能在这里有一个误解,但是Parent中的列表数组以某种方式保留了值,我不知道为什么.
这是一个很大的麻烦,因为如果我将Parent类重用于许多其他子类(如上面的情况),如果Parent将数组变量共享给其子类,则该值也将共享给其他子类,这是意外的我.
我所预期的那样,在儿童类表示新的对象,同样进入到父类时,子类被初始化为OBJ1,然后当我初始化新的子对象OBJ2,从推值OBJ1不应与共享obj2的.
- 题 -
任何人都可以帮我找出为什么上面例子中的列表(Parent的数组变量)保留值/共享由Child对象启动的值(在上面的例子中,obj1和obj2)?
如果你有另一个可以解决这个问题的解决方案,那将是非常好的,但我很乐意首先找出问题.
T.J*_*der 12
当子对象具有从其原型对象继承的属性时,实际发生的是该子对原型的引用,该原型包含该属性.孩子没有自己的副本.因此,两个孩子都使用相同的数组 - Parent
您分配给的(一个)原型对象上的数组Child.prototype
.
先是一些图片,然后是更多文字.:-)
new Parent()
给你这个:
+-----------------+ | Parent instance | +-----------------+ | list = [] | +-----------------+
...然后你分配给它Child.prototype
.
然后,new Child()
给你这个:
+------------------+ | Child instance 1 | +------------------+ +-----------------+ | (prototype) |------->| Parent instance | +------------------+ +-----------------+ | list = [] | +-----------------+
这样做new Child()
再次为您提供了另一个问题:
+------------------+ +------------------+ | Child instance 1 | | Child instance 2 | +------------------+ +------------------+ | (prototype) |---+ | (prototype) |---+ +------------------+ | +------------------+ | | | | | +-----------------+ +-------------------------+---->| Parent instance | +-----------------+ | list = [] | +-----------------+
正如您所看到的,所有Child
实例都共享相同的Parent
实例(它们的原型),它上面有一个数组.
当你说:
var obj = new Child();
obj.list.push("foo");
Run Code Online (Sandbox Code Playgroud)
...这是JavaScript引擎在看到时所做的事情obj.list
:
obj
有自己的属性调用list
.如果没有,那么:obj
原型是否有自己的属性叫做list
.如果没有,那么:obj
原型的原型是否有自己的属性叫做list
.在您的情况下,由于obj
没有自己的 list
属性,引擎会查看其原型(Parent
您分配给的实例Child.prototype
),在这种情况下确实具有该属性.所以使用了一个.它没有复制到孩子或任何东西,它被使用.当然,因为它是一个数组,所以在数组上推送一些东西实际上会把它推到数组上.
如果你要分配一些东西obj.list
,那么obj
就会得到自己的 list
财产,打破链条.所以把this.list = [];
在Child
将给予每个孩子自身的列表.
每当原型在其上有对象引用时,您就会看到这一点,其中对象是可以修改的类型("可变"对象).数组,日期,普通对象({}
),RegExps等,它们都有状态,它们都可以被修改,所以你可以用它们看到它.(String
实例是不可变的,所以尽管发生同样的事情,但是你看不到任何影响,因为字符串不能改变.)
对于原语,虽然你继承它们,但你不能改变它们的状态(你只能用一个具有不同状态的新原语替换它们),所以你看不到同样的效果.所以,如果obj
继承的财产foo
从它的原型,foo
是42
,alert(obj.foo)
将获得从样机,并显示"42"的值.改变的唯一方法foo
是说obj.foo = 67
或类似 - 它给出obj
了自己的副本foo
,与原型的副本不同.(这是真实的,即使你用的东西喜欢++
和--
,例如++obj.foo
,真正得到的评价obj.foo = obj.foo + 1
).