Javascript 中经典原型制作方法中的“this”是如何工作的

How `this` works from a Classical Method of Prototyping in Javascript

我正在 Javascript 学习面向对象编程。 我从这里 http://www.objectplayground.com/ 获得了这个视频课程,我对经典方法的原型方法有了相当多的了解。

在观看课程时,我被下面显示的经典方法与子类一起工作的示例暂停了:

//superclass
function Answer(value){
     this._val = value;
}

//define prototype property 'get' for the superclass
Answer.prototype.get = function fn1(){
    return this._val;
}

//subclass
function FirmAnswer(value){
    Answer.call(this,value);
}

FirmAnswer.prototype = Object.create(Answer.prototype);
FirmAnswer.prototype.constructor = FirmAnswer;

//define prototype property 'get' for subclass
FirmAnswer.prototype.get = function fn2(){
   return Answer.prototype.get.call(this);
}


var luckAnswer = new FirmAnswer(7);
luckAnswer.get(); //7

问题:

根据我对 call 函数的理解,它将 this 设置为当前上下文,例如来自 FirmAnswer 函数的这一行 Answer.call(this,value),因此 Answer 中的 _val 将设置为 FirmAnswer 而不是 Answer (如果我错了请纠正我)。

所以如果上面的分析是正确的,那么我很困惑,为什么 get 属性 of the FirmAnswer.prototype returns Answer.prototype.get.call(this)而不仅仅是 Answer.prototype.get(),因为在调用 new FirmAsnwer(7)?

this 已经设置为 FirmAnswer

请给我一些启发,因为我现在很困惑。我很确定我很了解原型方法,但经典方法让我很困惑。

提前致谢!

既然你编辑了代码,就没有必要了:

//define prototype property 'get' for subclass
FirmAnswer.prototype.get = function fn2(){
   return Answer.prototype.get.call(this);
}

因为 FirmAnswer.prototype 在您执行此操作时已经具有 get 函数:

FirmAnswer.prototype = Object.create(Answer.prototype);

它将get函数从Answer.prototype复制到FirmAnswer.prototype

所以,你可以删除它:

//superclass
function Answer(value){
     this._val = value;
}

//define prototype property 'get' for the superclass
Answer.prototype.get = function fn1(){
    return this._val;
}

//subclass
function FirmAnswer(value){
    Answer.call(this,value);
}

FirmAnswer.prototype = Object.create(Answer.prototype);
FirmAnswer.prototype.constructor = FirmAnswer;

var luckAnswer = new FirmAnswer(7);
luckAnswer.get(); //7

不相关,因为编辑问题

这是一段奇怪的代码,包含一个错误和其他无法解释的地方。

错误是这一行:

FirmAnswer.prototype.get = Object.create(Answer.prototype);

这显然是无意义的代码,尤其是当 FirmAnswer.prototype.get 在两行之后被设置为更合理的代码时。我相当确定它应该是:

FirmAnswer.prototype = Object.create(Answer.prototype);

这是 ES6 之前的原型继承的正常方式 Javascript。

结束无关紧要

我不明白为什么 FirmAnswer.prototype.get 被设置为另一个方法,一旦上述错误被修复,无论如何调用都会被委托给 Answer.prototype.get

但是,您问了一个具体问题:为什么需要这一行:

return Answer.prototype.get.call(this);

为什么我们不能 Answer.prototype.get()?当我们执行 Answer.call(this,value); 时,它仅为该调用设置上下文(this 值)。它只影响构造函数。如果你做了 Answer.prototype.get(),函数调用的上下文实际上是 Answer.prototype,它没有 _val 属性.

然而,这都是无关紧要的,因为实际上并不需要该方法。这是更合理形式的代码:

//superclass
function Answer(value){
     this._val = value;
}

//define prototype property 'get' for the superclass
Answer.prototype.get = function fn1(){
    return this._val;
}

//subclass
function FirmAnswer(value){
    Answer.call(this,value);
}

FirmAnswer.prototype = Object.create(Answer.prototype);
FirmAnswer.prototype.constructor = FirmAnswer;

var luckAnswer = new FirmAnswer(7);
console.log(luckAnswer.get()); //7

函数 FirmAnswers 构造函数正在将其传递给函数 Answer,其中 Answer 正在设置 this._val。因此,如果您要在控制台中查看 luckanswer FirmAnswer { _val: 7 }

是FirmAnswer类型的对象,_val为7

当您将 FirmAnswer.prototype.get 设置为一个命名的匿名函数,该函数 returns 调用 Answer.prototype.get 您再次将 FirmAnswers this 传递给原型,该原型基本上是复制原型.