Javascript继承:父';s数组变量保留值
我在这里尝试在JavaScript中使用继承,发现在父类中存在由子类继承的数组值问题。以下代码是正常继承:Javascript继承:父';s数组变量保留值,javascript,oop,inheritance,Javascript,Oop,Inheritance,我在这里尝试在JavaScript中使用继承,发现在父类中存在由子类继承的数组值问题。以下代码是正常继承: var Parent = function() { this.list = []; }; var Child = function() {}; Child.prototype = new Parent; Child.prototype.constructor = Child; var obj1 = new Child; obj1.list.push("hello"); c
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"];
当我将新的子对象初始化到obj1并尝试使用值“hello”推送obj1.list时,obj1.list打印[“hello”]。。到目前为止还不错
当我执行上面的示例时,出现了问题,我尝试将新的子对象初始化为obj2,然后用值“再见”按obj2的list,而obj2.list现在打印[“你好”,“再见”]。(请参见下面的代码:)
我在这里可能有一个误解,但是Parent中的list数组以某种方式保留了该值,我不知道为什么
这是一个很大的问题,因为如果我将父类重用到许多其他子类(如上述情况),如果父类将数组变量共享到其子类,那么该值也将共享到其他子类,这对我来说是意外的
我所期望的是,Child类代表新对象,当Child类初始化为obj1时,父类也代表新对象,然后当我将newChild对象初始化为obj2时,obj1的推送值不应与obj2共享
--问题:--
有人能帮我找出为什么上例中的列表(父对象的数组变量)保留值/共享子对象启动的值(在上述情况下,obj1和obj2)
如果您有另一个解决方案可以解决这个问题,那将非常感谢您,但我很高兴首先找到上面的问题。当子对象具有从其prototype对象继承的属性时,真正发生的是子对象具有对包含该属性的prototype的引用。孩子没有自己的副本。因此,两个子对象都使用同一个数组,即您分配给
Child.prototype
的(一)父对象上的数组
首先是一些图片,然后是更多文本。:-)
newparent()
为您提供以下信息:
+-----------------+
| Parent instance |
+-----------------+
| list = [] |
+-----------------+
+------------------+
| Child instance 1 |
+------------------+ +-----------------+
| (prototype) |------->| Parent instance |
+------------------+ +-----------------+
| list = [] |
+-----------------+
再次执行new Child()
将为您提供另一个:
+------------------+ +------------------+
| Child instance 1 | | Child instance 2 |
+------------------+ +------------------+
| (prototype) |---+ | (prototype) |---+
+------------------+ | +------------------+ |
| |
| | +-----------------+
+-------------------------+---->| Parent instance |
+-----------------+
| list = [] |
+-----------------+
…下面是JavaScript引擎在看到obj.list
时所做的操作:
查看obj
是否有自己的名为list
的属性。若否,则:
查看obj
的原型是否有自己的名为list
的属性。若否,则:
查看obj
的原型的原型是否有自己的名为list
的属性
等等,直到我们的原型用完
在您的情况下,由于obj
没有自己的list
属性,因此引擎会查找其原型(您分配给Child.prototype
的Parent
实例),在本例中,该实例确实具有该属性。所以就用这个。它不是复制给孩子或任何东西,而是被使用的。当然,因为它是一个数组,在数组上推动某个东西实际上会把它推到数组上
如果要将某个内容分配给obj.list
,则obj
将获得其自己的list
属性,从而打破链。所以把this.list=[]Child
中的code>将为每个孩子提供自己的列表
每当原型上有对象引用时,您就会看到这一点,其中对象是可以修改的类型(“可变”对象)。数组、日期、普通对象({}
),regexp等等,它们都有状态,都可以修改,所以您可以看到它们。(String
实例是不可变的,因此尽管发生了同样的情况,但您看不到任何效果,因为字符串无法更改。)
对于基本体,虽然您继承了它们,但无法更改它们的状态(只能用具有不同状态的新基本体替换它们),因此您看不到相同的效果。因此,如果obj
从其原型继承属性foo
,并且foo
是42
,alert(obj.foo)
将从原型获得值并显示“42”。更改foo
的唯一方法是说obj.foo=67
或类似的-这使obj
拥有自己的foo
副本,与原型副本不同。(即使你使用像++
和--
这样的东西,例如++obj.foo
,这也是正确的;它实际上被评估为obj.foo=obj.foo+1
)。这里缺少的是父.list
只被实例化一次;当您将其“原型”复制到Child.prototype
中时
在JavaScript中实例化“子类”不会自动调用父构造函数。因此,Child
的所有实例将共享相同的数组实例
修改Child
的构造函数以调用父构造函数应该是治疗您疾病的良方:
var Child = function() {
Parent.call(this);
};
显然,你已经对这个主题有了一些了解,但如果你感兴趣,这里有一些关于这个主题的文章值得一读:
因为两个实例都引用了与原型相同的父实例,因此引用了相同的数组。这里有很多JavaScript OOP问题,您应该看看它们。可能的重复和您令人敬畏的ascii图形保证超过+1,但这是唯一的
var obj = new Child();
obj.list.push("foo");
var Child = function() {
Parent.call(this);
};