为什么基类的对象属性与子类的所有实例共享?

Why is the object property of my base class shared with all instances of subclasses?

本文关键字:实例 共享 基类 对象 属性 为什么 子类      更新时间:2023-09-26

我试图理解我在这个小提琴上重新创造的行为。

function BaseObject(){}
BaseObject.prototype.value = 1;
BaseObject.prototype.obj = {value:1};
BaseObject.prototype.log = function() {
    console.log(this.constructor.name + " - Value: " + this.value);
    console.log(this.constructor.name + " - ObjValue: " + this.obj.value);
};
BaseObject.prototype.add = function(i) {
    this.value += i;
    this.obj.value += i;
};
function Derivation1(){}    
Derivation1.prototype = Object.create(BaseObject.prototype);
Derivation1.prototype.constructor = Derivation1;
function Derivation2(){}
Derivation2.prototype = Object.create(BaseObject.prototype);
Derivation2.prototype.constructor = Derivation2;
var first = new Derivation1();
var second = new Derivation2();
first.log();
first.add(1);
first.log();
second.log();

输出是:

Derivation1 - Value: 1
Derivation1 - ObjValue: 1
Derivation1 - Value: 2 <-- as expected
Derivation1 - ObjValue: 2 <-- as expected
Derivation2 - Value: 1
Derivation2 - ObjValue: 2 <-- Why is this two too and not 1?

该行为表明,对象成员被所有实例共享或以静态方式访问,而原始成员每个都驻留在自己的实例中。

有人能解释一下吗?

其实很简单——原型并没有被深度复制。所有的对象都有相同的obj实例,因为您永远不会为每个对象创建一个新的obj

只要为可变属性使用构造函数(或者一些初始化函数,如果你喜欢的话)。这会给你省去很多麻烦。

function BaseObject() {
  this.value = 1;
  this.obj = { value:1 };
}
BaseObject.prototype.log = function() {
  console.log(this.constructor.name + " - Value: " + this.value);
  console.log(this.constructor.name + " - ObjValue: " + this.obj.value);
};
BaseObject.prototype.add = function(i) {
  this.value += i;
  this.obj.value += i;
};
function Derivation1(){
  BaseObject.call(this);
}
Derivation1.prototype = Object.create(BaseObject.prototype);
Derivation1.prototype.constructor = Derivation1;
function Derivation2(){
  BaseObject.call(this);
}
Derivation2.prototype = Object.create(BaseObject.prototype);
Derivation2.prototype.constructor = Derivation2;
var first = new Derivation1();
var second = new Derivation2();
var third = new Derivation1();
first.log();
first.add(1);
first.log();
second.log();
third.log();

注意添加的third实例—如果您将它添加到代码中,您将看到它共享相同的obj实例。实际上,您的obj是一个"静态属性"-尽管它不是只读的,所以您可以在任何实例中替换它。

另一件重要的事情是,您必须在派生构造函数中手动调用父构造函数- Object.create创建一个未初始化的对象。