构造函数原型-继承混淆

Constructor prototype - inheritance confusion

本文关键字:继承 原型 构造函数      更新时间:2023-09-26

我首先定义两个独立的构造函数。

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

我现在希望"类"传奇之剑的所有实例都具有剑"类"的特性,即攻击和价格值。这是因为所有传说中的剑最终都是剑,但具有一些独特的特性(如"instantKill"(。

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

LegendarySword.prototype = new Sword();

我理解这句话的方式是,当我构建传奇之剑类的新对象时,除了传奇之剑已经拥有的构造函数之外,我还使用了剑的构造函数。我希望传说之剑的物体获得攻击和价格属性,但同时我不希望剑的物体得到instantKill属性。

我还希望我现在能够在传奇之剑构造函数中提供论据:

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)

看起来我仍然可以从另一端解决问题。如果我有点像我认为的那样,不必要地使构造函数复杂化,并向Sword添加新方法,并在创建新的Legendary 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不能弄清楚需要添加新的属性?这对我来说太直观了。

有没有其他方法可以解决这个问题?

我希望这能像Sword构造函数一样接受争论,但显然不是:

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

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

这并不能证明这一点。您不知道该属性是否存在,因为访问不存在的属性也会返回未定义(这就是本例中实际发生的情况(。

当你这样做:

LegendarySword.prototype = new Sword();

您只需将传奇之剑的默认原型替换为剑说之剑本身,因此构造函数不会添加攻击价格属性。

如果您希望传奇之剑的实例具有与s相同的属性,您可以执行以下操作:

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

它设置了所需的原型链,并使用属性初始化传奇剑

仅解决方案

要解决你的问题,你只需要做:

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

所以在这种情况下,你甚至不需要使用原型:你只需要在子函数中调用父函数并传递新的this。

原型继承

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函数的新实例。

因此,最好将其放在原型中