【问题标题】:How `this` works from a Classical Method of Prototyping in Javascript`this` 如何从 Javascript 中的经典原型方法中工作
【发布时间】:2017-06-12 11:44:31
【问题描述】:

我正在学习 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(如果我错了,请纠正我)。

因此,如果上述分析正确,我会感到困惑,为什么FirmAnswer.prototypeget 属性返回Answer.prototype.get.call(this) 而不仅仅是Answer.prototype.get(),因为this 已经设置为FirmAnswer 什么时候打电话给new FirmAsnwer(7)

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

提前感谢您!

【问题讨论】:

标签: javascript prototype-programming prototype-chain prototype-pattern


【解决方案1】:

既然你编辑了代码,就不需要这样了:

//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 我打错了。我的道歉
【解决方案2】:

编辑问题后不相关

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

错误是这一行:

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

【讨论】:

  • 对不起FirmAnswer.prototype.get 我打错了。我的道歉
  • @Roljhon 对不起,你是什么意思?
  • 我更新了代码,代码其实不是这样的,很简单的FirmAnswer.prototype,因为它为函数FirmAnswer创建了一个原型对象,对不起,我的错误,没有注意到了。
  • @Roljhon 我的答案仍然有效,尽管第一部分现在无关紧要。我已经这样标记了。
  • 我刚刚从课程中得到代码,所以这意味着this 实际上设置为FirmAnswer 对吗?添加的Answer.prototype.get.call(this); 实际上让我感到困惑,因为在这种情况下它就像是多余的。但是,感谢您向我澄清不再需要它。所以现在更清楚了
【解决方案3】:

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

它是一个 FirmAnswer 类型的对象,_val 为 7

当您将 FirmAnswer.prototype.get 设置为返回对 Answer.prototype.get 的调用的命名匿名函数时,您再次将 FirmAnswers 传递给原型,该原型基本上是制作原型的副本。

【讨论】:

  • 我认为我们的理解与FirmAnswer 的上下文如何传递给Answer 相同,但是,从我在问题中指出的角度来看。为什么不直接使用Answer.prototype.get() 而不是Answer.prototype.get.call(this)?然后?因为this 已经分配给FirmAnswer,所以根据我的理解不需要call,因为如果已经设置了上下文,为什么我们需要将上下文设置为FirmAnswer
猜你喜欢
  • 1970-01-01
  • 2013-11-07
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-15
  • 2013-05-25
  • 2010-11-16
相关资源
最近更新 更多