【问题标题】:Prototypical inheritance: how to get instanceof?原型继承:如何获取 instanceof?
【发布时间】:2017-10-02 06:25:47
【问题描述】:

看了这个video之后,我了解到了一种用Javascript实现继承的好方法:原​​型继承。此方法使用 Object.create/Object.assign 基于另一个实例创建新对象。这似乎很有趣,因为很容易理解正在发生的事情。例如:

const human = {
  species: 'human',
  create: function(values) {
    const instance = Object.create(this);
    Object.assign(instance, values);
    return instance;
  },
  sayName: function() {
    console.log(`Hi, my name is ${this.name}`);
  },
  saySpecies: function() {
    console.log(`Hi, I'm a ${this.species}`);
  }
}

const musician = human.create({
  species: 'musician',
  playInstrument: function() {
    console.log(`I'm a musician and I play ${this.instrument}`);
  }
});

const aHuman = human.create({ name: 'Paul' });
aHuman.sayName();
aHuman.saySpecies();

const aMusician = musician.create({ name: 'David', instrument: 'Guitar' });
aMusician.sayName();
aMusician.saySpecies();
aMusician.playInstrument();

// how to check if musician is an instance of human?
console.log(musician instanceof human);

通过经典继承,我可以使用instanceof 来了解给定对象是否在其链中具有给定的proto(例如musician instanceof Human)。

这就是 proto 链的样子,看起来与使用 new 运算符创建的链非常相似。

问题 如何通过原型继承实现同样的目标?

【问题讨论】:

  • 您的代码没有使用Object.create
  • 对不起,让我扩充示例以显示正在使用的 Object.create。
  • 完成。感谢您指出这一点。
  • 它仍然不使用Object.create
  • 我只是将 Object.create 替换为 Object.assign ,它确实会创建一个对象的新实例。让我更新一下问题。

标签: javascript inheritance prototype


【解决方案1】:

您的尝试有两个主要问题:

  • instanceof 的 RHS 必须是一个函数,因此您的类型必须建立在函数之上。
  • 您没有区分静态/类型方法和实例方法。 create 是一种类型方法。 sayName 是一个实例方法。

以下应该按您的预期工作。

function Human(){}

Object.assign(Human, {
  create: function(values) {
    let newObj = Object.create(this.prototype);
    return Object.assign(newObj, values);
  }
});

Object.assign(Human.prototype, {
  species: 'human',
  sayName: function() {
    console.log(`Hi, my name is ${this.name}`);
  },
  saySpecies: function() {
    console.log(`Hi, I'm a ${this.species}`);
  }
});

function Musician(){}

Object.assign(Musician, Human);

Musician.prototype = Human.create({
  species: 'musician',
  playInstrument: function() {
    console.log(`I'm a musician and I play ${this.instrument}`);
  }
});

const aHuman = Human.create({ name: 'Paul' });
aHuman.sayName();
aHuman.saySpecies();

const aMusician = Musician.create({ name: 'David', instrument: 'Guitar' });
aMusician.sayName();
aMusician.saySpecies();
aMusician.playInstrument();

// how to check if musician is an instance of human?
console.log(aMusician instanceof Human);

【讨论】:

  • 谢谢。这个解决方案有效。但如果我使用函数,我想最好使用经典继承。我已经发布了另一个答案,我在人体对象中实现了instanceof 函数。
【解决方案2】:

您的代码不使用继承。唯一创建新对象的地方就是这一行:

    return Object.assign({}, this, values);
//                       ^^ here

{} 创建一个继承自 Object.prototype 的新对象。这就像在做Object.create(Object.prototype)new Object()

您的代码中没有任何内容继承自 humanmusician

【讨论】:

  • 非常好的观点。我在错误的地方使用了对象分配。我需要使用 Object.create 来保持 proto 链。让我再次更新我的问题。
  • 我刚刚更新了我的问题。我为音乐家 proto 对象添加了截图
【解决方案3】:

@JLRishe 的回答有效。但是,如果您想避免使用函数并继续使用对象,您可以实现自己的 instanceof 版本。这段代码 sn-p 也可以:

const human = {
  species: 'human',
  create: function(values) {
    let newObj = Object.create(this);
    return Object.assign(newObj, values);
  },
  instanceof: function(obj) {
    if (!Object.getPrototypeOf(this)) {
      return false;
    }
    let isPrototypeOf = (
      this === obj ||
      Object.getPrototypeOf(this) === obj ||
      this === Object.getPrototypeOf(obj) ||
      Object.getPrototypeOf(this) === obj.prototype
    );
    if (!isPrototypeOf) {
      isPrototypeOf = this.instanceof.call(Object.getPrototypeOf(this), obj);
    }
    return isPrototypeOf;
  },
  sayName: function() {
    console.log(`Hi, my name is ${this.name}`);
  },
  saySpecies: function() {
    console.log(`Hi, I'm a ${this.species}`);
  }
}

const musician = human.create({
  species: 'musician',
  playInstrument: function() {
    console.log(`I'm a musician and I play ${this.instrument}`);
  }
});

const aHuman = human.create({ name: 'Paul' });
aHuman.sayName();
aHuman.saySpecies();

const aMusician = musician.create({ name: 'David', instrument: 'Guitar' });
aMusician.sayName();
aMusician.saySpecies();
aMusician.playInstrument();

var test = {};

console.log(human.instanceof(human));
console.log(musician.instanceof(human));
console.log(musician.instanceof(Object));
console.log(aHuman.instanceof(human));
console.log(aMusician.instanceof(human));
console.log(aHuman.instanceof(musician));
console.log(aHuman.instanceof(Object));
console.log(aMusician.instanceof(musician));
console.log(musician.instanceof(test));
console.log(human.instanceof(test));
console.log(aMusician.instanceof(test));
console.log(aHuman.instanceof(test));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-07
    • 2013-05-20
    • 2010-09-28
    • 2018-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多