【问题标题】:calling prototype methods from javascript constructor从 javascript 构造函数调用原型方法
【发布时间】:2015-10-10 00:59:06
【问题描述】:

我有以下简单的继承模式,我想知道是否可以按照我在构造函数中的方式调用方法(基本上,使用this 而不是“超级原型”。

父类,Pet

function Pet(name) {
  this.name = name;
  this.nickname = name;

  this.adopt();
}

Pet.prototype.adopt = function() {
  this.nickname = 'Cutty ' + this.name;
}

Pet.prototype.release = function() {
  this.nickname = null;
}

Pet.prototype.cuddle = function() {
  console.log(this.name + ' is happy');
}

子类,Lion

function Lion(name) {
  Pet.prototype.constructor.apply(this, arguments); // super(name)
  this.cuddle();
  this.release();
}
Lion.inherits(Pet);

Lion.prototype.adopt = function() {
  // DTTAH
}

Lion.prototype.release = function() {
  Pet.prototype.release.call(this);
  console.log('Thanks for releasing ' + this.name);
}

inherits 助手(我知道 polyfill 很糟糕)

Function.prototype.inherits = function(Parent) {
  function ProtoCopy() {}
  ProtoCopy.prototype = Parent.prototype;

  this.prototype = new ProtoCopy();
  this.prototype.constructor = this;
}

我的宠物像这样被实例化var lion = new Lion('Simba')

在 Lion 构造函数中,
我可以在调用子/父类方法时继续使用this 吗?或者我应该直接使用父原型中的方法吗? (例如对super()release() 的伪调用)

我问的原因是:

  • this 运行时替换
  • constructor 财产并不总是我们所想的(从我在这里和那里读到的)

我不确定这些东西如何影响生成的对象。

感谢您的启发!

【问题讨论】:

  • 你的inherits函数有副作用,我推荐使用Object.create
  • 您应该在任何地方省略.prototype.constructor 部分。
  • Pet.prototype.constructor.release(); 超级调用是错误的。你的意思可能是Pet.prototype.release.call(this);
  • 我不想提供这个作为一个完整的答案,而是一个建议考虑看看 Klass.js github.com/ded/klass - 它允许轻松调用 this.super()
  • @elclanrs 有什么副作用?这是我最自信的部分!

标签: javascript inheritance methods constructor


【解决方案1】:

在构造函数中使用this.fn()MyClass.prototype.fn.call(this)有什么区别?

这并不特定于构造函数,在实例上调用的所有函数(方法)中都是相同的。

确实,this.fn === MyClass.prototype.fn 时除了字符数之外没有太大区别,它们的行为完全相同。然而,这个假设并不总是正确的 - this 可能不会直接继承自 MyClass.prototype,而是一个子类实例,并且该子类可能覆盖 @ 987654327@方法。

那么哪一个是正确的?两者,事实上。如果您知道其中的区别,您可以根据自己的情况选择合适的。其他语言在此处有不同的默认期望,另请参阅calling static methods

请注意,您不能用this.constructor 替换类引用,这也会被覆盖。在合理的设置中1this.fn() 将始终等价于 this.constructor.prototype.fn.call(this)

这类似于 super 调用必须显式引用超类而不依赖于实例属性(例如 this.constructorthis.super 或类似的东西)的原因。

1:其中this.fn 是从原型继承的常用方法,而不是自己的实例特定方法,并且每个原型都有.constructor 指向其.prototype 的相应构造函数。

【讨论】:

  • 关于这部分:“注意你不能用 this.constructor 替换类引用,它也会被覆盖”你是在说一个明确的和有针对性的覆盖constructor 属性或其他操作的副作用?
  • 是的,当子类化 .constructor 时被显式覆盖。您必须使用Pet,而不是this.constructor,因为后者可能引用Lion
【解决方案2】:

简化问题,考虑 ES6 中的以下代码:

class Pet {
  constructor (name) {
    this.name = name;
    this.talk();
  }
  talk () {
    console.log('My name is ' + this.name);
  }
}

class Lion extends Pet {
  constructor (name) {
    super(name);
  }
  talk () {
    super.talk();
    console.log('I am a lion.');
  }
}

相当于:

function Pet (name) {
  this.name = name;
  this.talk();
}
Pet.prototype.talk = function () {
  console.log('My name is ' + this.name);
};

function Lion (name) {
  Pet.call(this, name);
}

// inheritance:
Lion.prototype = Object.create(Pet.prototype);
Lion.prototype.constructor = Lion;

// override .talk
Lion.prototype.talk = function () {
  Pet.prototype.talk.call(this);
  console.log('I am a lion');
}

运行new Lion('Bobby') 日志:

My name is Bobby
I am a lion

延伸阅读:http://eli.thegreenplace.net/2013/10/22/classical-inheritance-in-javascript-es5

【讨论】:

  • 您的示例中是否缺少继承部分?我得到lion instanceof Pet === false
  • @Jordan 啊,我的错,我忘记了那部分。现在有两行将返回 lion instanceof Pet 为真。文章里也有,忘记了。
猜你喜欢
  • 1970-01-01
  • 2017-11-11
  • 2015-04-06
  • 2013-05-08
  • 1970-01-01
  • 2018-08-20
  • 2013-08-10
  • 2017-08-21
  • 1970-01-01
相关资源
最近更新 更多