【问题标题】:How to inherit right from parent prototype JS如何从父原型JS继承权利
【发布时间】:2018-06-14 16:56:34
【问题描述】:

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

我知道我们可以轻松解决并将 this.walk 方法移到构造函数 Animal 后面并创建原型方法 Animal.prototype.walk... 但我想知道我们是否可以在不将 this.walk 推出构造函数的情况下做到这一点括号?这是一些 JS 技巧吗?

我将不胜感激,谢谢!

function Animal(name) {
  this.name = name;

  this.walk = function() {
    console.log( "walk " + this.name );
  };

}

// Animal.prototype.walk = function() {   //// we can not use this trik and 
//    console.log( "walk " + this.name ); //// delete this.walk function in 
//}                                       //// constructor


function Rabbit(name) {
  Animal.apply(this, arguments);
}

Rabbit.prototype = Object.create(Animal.prototype);
Rabbit.prototype.constructor = Rabbit;

Rabbit.prototype.walk = function() {
  console.log( "jump " + this.name );
};

var rabbit = new Rabbit("Rabbit");
rabbit.walk(); // for now we get "walk Rabbit". But need - "jump Rabbit"

【问题讨论】:

  • 我们不能使用这个技巧” - 为什么不呢?你应该这样做。
  • @Bergi 是的,我知道,但还有其他方法吗?问题是有几次我遇到了具有这种继承性的父原型,实际上我们不允许从构造函数中获取方法,将它们制作成原型。
  • "实际上我们不允许从构造函数中获取方法" - 我认为你需要解决这个问题,而不是寻找比显而易见的更好的解决方法.

标签: javascript inheritance constructor prototype


【解决方案1】:

如果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,但这可能会让任何认为该方法被继承的读者感到困惑)

【讨论】:

  • 太棒了!但是,通过这种方式,我们需要将子原型方法 .prototype.walk 移动到 Rabbit 构造函数(如 this.walk)。我们能否制作出在父构造函数中包含父 .walk 方法和像子原型一样的 Rabbit.prototype.walk 方法的解决方案?
【解决方案2】:

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) 直接在rabbit 实例上添加了walk 函数。

解决这个问题的方法是在原型上定义两个walk 方法both(首选)或在构造函数主体中both


或者,您可以利用 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"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 2021-09-04
    • 1970-01-01
    • 1970-01-01
    • 2016-08-06
    相关资源
    最近更新 更多