修改孩子的原型会影响父母的原型吗?

时间:2014-08-31 01:40:13

标签: javascript

虽然下面的实现看起来不错,但是因为它允许孩子拥有自己的成员副本(无法修改父成员),而且它使用原型链,因此不会为每个成员重新创建属性对象实例化,它是无效的,因为Parent构造函数被调用两次(一次用于apply和新的Parent实例化):

function Parent(a,b,c,d){
  this.a = a;
  this.b = b;
  this.c = c;
  this.d = d;
}

Parent.prototype.say_a = function(){
  return this.a;
}

Parent.prototype.say_b = function(){
  return this.b;
}

Parent.prototype.say_c = function(){
  return this.c;
}

Parent.prototype.say_d = function(){
  return this.d;
}

Parent.prototype.not_going_to_be_copied = function(){
  console.log(“This function will not be recreated from one object instantiation to the next, making it very efficient.”);
}


function Child(a,b,c,d){
  Parent.apply(this,arguments);
}
Child.prototype = new Parent();
c = new Child("a","b","c","d");
console.log([c.say_a(),c.say_b(),c.say_c(),c.say_d()].join(" "));

Javascript模式中的Stoyan提到了这个替代方案,它根本不会调用Parent构造函数:

Child.prototype = Parent.prototype;

然而,他说这样做的一个缺点是,如果继承链附近的某个孩子或孙子修改原型,它会影响所有父母和祖父母。

但是,我无法重现这种说法:

function Parent(){}

Parent.prototype.set_a = function(a){
  this.a = a;
}

Parent.prototype.get_a = function(){
  return this.a;
}

function Child(){}
Child.prototype = Parent.prototype;

var c = new Child();
var p = new Parent();
c.set_a("a");
console.log(c.get_a()); // a
p.set_a("b");
console.log(p.get_a()); // b
console.log(c.get_a()); // a
c.prototype = {};
console.log("after mod " + c.get_a()); // after mod a
console.log("after mod " + p.get_a()); // after mod b
c.get_a = function(){return "am I changing parent?"}
console.log(c.get_a()); // am I changing parent?
console.log(p.get_a()); // b

如您所见,无论我如何修改Child的原型,它都不会影响Parent的原型。我错过了什么吗?孩子们对原型的修改是否会对父母产生影响?

2 个答案:

答案 0 :(得分:1)

Child.prototype = Parent.prototype之后,同一个对象绑定到两个构造函数的prototype属性(并且相当愚蠢,IMOHO)。因此,修改称为Child.prototype 的对象也会修改Parent.prototype“影响所有”,因为两个表达式都会计算同一个对象

稍后考虑一下;

Child.prototype.hello = "Hello world"
// Noting that
Child.prototype === Parent.prototype  // -> true, as per initial condition

然后;

var p = new Parent()
p.hello                  // -> "Hello world", showing the "affecting" behavior    

因此,可以看到修改Child.prototype也影响了Parent实例的[原型] - 因为修改了同一个对象

然而,问题没有被复制,因为人们不能以这种方式“分配实例的原型”。也就是说,在创建新实例时,[prototype]链仅基于构造函数的原型属性(或通过Object.create)设置 。分配给实例的prototype属性是..只需分配一个普通的属性。

var c = new Child()
c.prototype = "Hello world"
typeof c.say_a                   // -> "function", didn't assign [prototype]
c.prototype                      // -> "Hello world"
c.__proto__ === Child.prototype  // -> true, in browsers supporting __proto__

答案 1 :(得分:1)

Child.prototype = Parent.prototype;

很糟糕,因为如果孩子是狗,而父母是动物我们可以说狗是动物,但我们不能说动物是狗(蛇怎么样?)。

这是出错的地方

var Animal=function(){};
var Snake = function(){};
Snake.prototype=Animal.prototype;
var Dog = function(){};
Dog.prototype=Animal.prototype;
Dog.prototype.bark=function(){console.log('I am barking');};

var aSnake = new Snake();
aSnake.bark();//I am barking ???

最好使用Object.crate来设置Child的原型,而不是将其设置为Parent的实例,因为Parent具有不应该在Child上的特定于实例的成员,并且您可能遇到Parent构造函数需要传递的参数的情况。在声明Child类型时不可用(并且它只是错误的形式)。

在您的代码c.get_a中隐藏原型成员并且不会影响原型。详细解释了here