构造函数原型 - 继承混淆

时间:2015-01-17 21:19:33

标签: javascript constructor prototype

我从定义2个独立构造函数开始。

var Sword = function (attack,price){
 this.attack = attack;
 this.price = price;
};

var LegendarySword = function (){
 this.instantKill = true;
};

这些构造函数创建的对象显然彼此无关。

var sword = new Sword(1, 100);
console.log(sword);

//Object
    attack: 1
    price: 100
    __proto__: Object


var superSword = new LegendarySword();
console.log(superSword);

//Object
    instantKill: true
    __proto__: Object

我现在希望“class”LegendarySword的所有实例都具有Sword“class”特征的属性,即攻击和价格值。这是因为所有传说中的剑最后都是剑,但具有一些独特的属性(如“instantKill”)。

因此,在阅读了原型和继承之后,我发现我可以笑着这样做:

LegendarySword.prototype = new Sword();

我理解这一行的方式是,除了我在构建LegendarySword类的新对象时LegendarySword已经拥有的内容之外,我还在使用Sword的构造函数。我希望LegendarySword对象获得攻击和价格属性,但同时我不希望Sword对象获得instantKill属性。

我还希望我现在可以在LegendarySword构造函数中提供参数:

var superSword2 = new LegendarySword (5, 1000);

我希望这会接受参数,就像Sword构造函数那样,但它显然不会:

console.log(superSword2.attack); // results to undefined (which proves that it has them dug in somewhere in the __proto__,  which is so indeed)

看起来我仍然可以解决从另一端接近它的问题。如果我有点,我认为,在创建新的Legendary Sword对象时,不必要地使构造函数复杂化并向Sword添加新方法并调用这些方法并传递参数:

var Sword = function (attack,price){
 this.attack = attack;
 this.price = price;
    this.setAttack = function(attack){
    this.attack = attack;
};
this.setPrice = function(price){
    this.price = price;
};
};

var LegendarySword = function (attack, price){
 this.instantKill = true;
 this.setAttack(attack);
 this.setPrice(price);

};

LegendarySword.prototype = new Sword();

var sword = new Sword(1, 100);
console.log(sword);// gives correct object attributes

var superSword = new LegendarySword(10,5000);
console.log(superSword); // gives correct object attributes

但这真的很难看,我的问题是为什么当我调整构造函数的原型时Javascript无法确定需要添加新属性?这对我来说非常直观。

是否有其他方法可以解决问题?

2 个答案:

答案 0 :(得分:2)

  

我希望这会接受参数,就像Sword构造函数那样,但它显然不会:

你不应该期望,修改构造函数的原型并不会修改构造函数本身。

> console.log(superSword2.attack);
> // results to undefined
> // (which proves that it has them dug in somewhere in
> //  the __proto__,  which is so indeed)

它没有证明这一点。您不知道该属性是否存在,因为访问不存在的属性也会返回 undefined (在这种情况下实际发生的情况)。

当你这样做时:

LegendarySword.prototype = new Sword();

您只需将 LegendarySword 的默认原型替换为 Sword 的实例,它不会修改 LegendarySword 本身,因此<构造函数不会添加em> attack 和 price 属性。

如果您希望 LegendarySword 的实例与 Sword 具有相同的属性,则可以执行以下操作:

var LegendarySword = function (attack, price){

  // Add Sword properties
  Sword.call(this, attack, price);

  // Add LegendarySword properties
  this.instantKill = true;
};

设置所需的原型链并使用 Sword 属性初始化 LegendarySword

答案 1 :(得分:1)

只是解决方案

要解决您的问题,您只需要这样做:

var Sword = function (attack,price){
 this.attack = attack;
 this.price = price;
};

var LegendarySword = function (attack, price){
 this.instantKill = true;
 Sword.call(this, attack, price)
};

var sword = new Sword(1, 100);
console.log(sword);// gives correct object attributes

var superSword = new LegendarySword(10,5000);
console.log(superSword); // gives correct object attributes

因此,在这种情况下,您甚至不需要使用原型:您只需在子项中调用父函数并传递新函数。

原型继承

JS中继承的基本解决方案是:

function basicInherit(Child, Parent) {
    var F = function () { };
    F.prototype = Parent.prototype;

    Child.prototype = new F();
    Child.prototype.constructor = Child;
    Child.super = Parent.prototype;
}

有时你可能不想调用父类的构造函数。另外我们不能只做Child.prototype = Parent.prototype,因为如果我们更改子原型,它将反映在父原型中。因此我们将原型从Parent复制到空F类,然后从F继承Child。

如果要继承原型属性,使用此类继承是有意义的,例如:

Sword.prototype.setPrice = function (price) { this.price = price; }

但无论如何 - 在新的子类中调用构造函数 - 这取决于你。

另一个建议

不要在JS中做这些事情:

var Sword = function (attack,price){
  this.attack = attack;
  this.price = price;
  this.setAttack = function(attack){
    this.attack = attack;
  };
}

因为每次创建新实例时都会创建一个新的setAttack函数实例。

所以,最好把它放在原型

相关问题