如何从父原型JS继承权利

时间:2018-01-04 21:52:17

标签: javascript inheritance constructor prototype

问题 - 如何将正确的方法从父(Animal)继承到子(Rabbit)原型,这些原型在创建对象后不会覆盖父原型道具,基于子原型。我的意思是,创建对象(兔子)必须从Rabbit原型获取原型方法(.prototype.walk),而不是从父级(Animal)。

我知道我们可以轻松解决并移动方法this.walk在构造函数Animal后面并创建原型方法Animal.prototype.walk ...但我想知道我们是否可以在不推送this.walk构造函数的情况下执行此操作括号?这是一些JS trik?

我会感激任何答案,谢谢!

BangPatterns

2 个答案:

答案 0 :(得分:2)

如果Animal构造函数在每个实例上定义.walk函数,要覆盖它们,Rabbit构造函数必须执行相同的操作:

function Rabbit(name) {
  Animal.apply(this, arguments); // creates an own .walk property

  // overwrites the own .walk property
  this.walk = function() {
    console.log( "jump " + this.name );
  };
}

您还可以共享函数对象以获得更好的内存使用:

function rabbitWalkMethod() {
  console.log( "jump " + this.name );
}
function Rabbit(name) {
  Animal.apply(this, arguments);
  this.walk = rabbitWalkMethod;
}

(您也可以使用Rabbit.prototype.walk属性来存储它而不是本地变量rabbitWalkMethod,但这可能会让任何认为该方法被继承的读者感到困惑)

答案 1 :(得分:1)

TL; DR:您正在混合使用两种不同的方法来定义JavaScript中的方法。你应该选择一种方法来坚持下去。

使用Animal,您将在构造函数体内定义walk方法。这将在每次调用构造函数时创建一个新函数。它易于阅读,但会浪费内存,因为每个实例都有自己相同的walk方法。

使用Rabbit,您正在利用Rabbit prototype,因此每个实例共享一个walk函数。您可以将JS中的原型视为备份对象。 JS首先在实例本身上查找属性。如果没有找到,它将在“原型链”上运行,直到它找到属性或用完原型。

例如,使用您的代码,如果我调用rabbit.toString(),我最终会向上移动链接:

rabbit.toString           --> undefined
Rabbit.prototype.toString --> undefined
Animal.prototype.toString --> undefined
Object.prototype.toString --> ƒ toString() { [native code] }

但是,当您致电rabbit.walk()时,它永远不会使它成为第一个原型,因为Animal.apply(this, arguments)walk函数直接添加到rabbit实例上。

解决此问题的方法是在构造函数体中定义两个walk方法两者(最好)或两者

或者,你可以利用ES6语法,它将你的walk方法放在后台的原型上,但看起来比手动更清晰:

class Animal {
  constructor (name) {
    this.name = name
  }

  walk () {
    console.log(`walk ${this.name}`)
  }
}

class Rabbit extends Animal {
  walk () {
    console.log(`jump ${this.name}`)
  }
}

const rabbit = new Rabbit('Rabbit')
rabbit.walk()  // "jump Rabbit"