Javascript继承:Parent的数组变量保留值

8 javascript oop inheritance

我在这里试图使用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对象启动的值(在上面的例子中,obj1obj2)?

如果你有另一个可以解决这个问题的解决方案,那将是非常好的,但我很乐意首先找出问题.

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:

  1. 看看是否obj自己的属性调用list.如果没有,那么:
  2. 看看obj原型是否有自己的属性叫做list.如果没有,那么:
  3. 看看obj原型的原型是否有自己的属性叫做list.
  4. 等等,直到我们用完原型.

在您的情况下,由于obj没有自己的 list属性,引擎会查看其原型(Parent您分配给的实例Child.prototype),在这种情况下确实具有该属性.所以使用了一个.它没有复制到孩子或任何东西,它被使用.当然,因为它是一个数组,所以在数组上推送一些东西实际上会把它推到数组上.

如果你要分配一些东西obj.list,那么obj就会得到自己的 list财产,打破链条.所以把this.list = [];Child将给予每个孩子自身的列表.

每当原型在其上有对象引用时,您就会看到这一点,其中对象是可以修改的类型("可变"对象).数组,日期,普通对象({}),RegExps等,它们都有状态,它们都可以被修改,所以你可以用它们看到它.(String实例是不可变的,所以尽管发生同样的事情,但是你看不到任何影响,因为字符串不能改变.)

对于原语,虽然你继承它们,但你不能改变它们的状态(你只能用一个具有不同状态的新原语替换它们),所以你看不到同样的效果.所以,如果obj继承的财产foo从它的原型,foo42,alert(obj.foo)将获得从样机,并显示"42"的值.改变的唯一方法foo是说obj.foo = 67或类似 - 它给出obj自己的副本foo,与原型的副本不同.(这是真实的,即使你用的东西喜欢++--,例如++obj.foo,真正得到的评价obj.foo = obj.foo + 1).

  • 你真棒的ascii图形保证超过+1,但这是我被允许奖励的全部 (5认同)