为什么这个不是这个
Why *this* is not *this*?
我刚刚写了这段代码来表示这个正在杀死我的错误(Grrr!(
我想知道为什么当我得到错误:方法未定义时,我在Safari中检查了parserIdStart((方法中的这个变量不是EpisodeController类型,而是EpisodeFeedParser类型,为什么会这样?
<html>
<head>
<script type="text/javascript">
var EpisodeFeedParser = function(url){
this.url = url;
this.didStartCallback = null;
};
EpisodeFeedParser.prototype.parse = function(doc){
this.didStartCallback(this);
};
var EpisodeController = function(){
this.episodes = new Array();
this.parser = null; //lazy
};
EpisodeController.prototype.parserDidStart = function(parser){
console.log("here *this* is not of type EpisodeController but it is EpisodeFeedParser Why?");
this.testEpi(); //**********ERROR HERE!***********
};
EpisodeController.prototype.fetchEpisodes = function(urlString){
if(urlString !== undefined){
if(parser === undefined){
var parser = new EpisodeFeedParser(urlString);
parser.didStartCallback = this.parserDidStart;
this.parser = parser;
}
this.parser.parse();
}
};
EpisodeController.prototype.testEpi = function(){
console.log("it worked!");
};
function testEpisode(){
var controller = new EpisodeController();
controller.fetchEpisodes("myurl");
}
</script>
</head>
<body>
<button type="button" onclick="testEpisode()">press me</button>
</body>
</html>
这是Javascript中一个经常被误解的方面。(我所说的"这个"是指this
(
您可以将this
视为另一个无形地传递给函数的参数。所以当你写一个函数,比如
function add (a,b) {
return a+b;
}
你真的在写
function add(this, a, b) {
return a+b;
}
这可能是显而易见的,不明显的正是传递的东西,并命名为"this"。其规则如下。有四种方法可以调用一个函数,每种方法都将不同的东西绑定到this
。
经典函数调用
add(a,b);
在经典函数调用中,this
绑定到全局对象。该规则现在被普遍认为是一个错误,在未来的版本中可能会被设置为null。
构造函数调用
new add(a,b);
在构造函数调用中,this
被设置为一个新对象,其内部(且不可访问(原型指针被设置为add.prototype
方法调用
someobject.add(a,b);
在方法调用中,this
被设置为someobject。最初在哪里定义add并不重要,无论它是在构造函数内部,还是特定对象原型的一部分,或者其他什么。如果你用这种方式调用一个函数,this
就会被设置为你调用它的任何对象。这就是你正在运行的规则。
调用/应用调用
add.call(someobject,a,b);
在call/apply调用中,this
被设置为传递给调用方法的现在可见的第一个参数的任何值。
代码中发生的情况是:
this.parser.didStartCallback = this.parserDidStart;
当你编写parserIdStart时,期望它的this
在方法调用它时会是一个EpicodeController…实际上,你现在正在将其this
从EpicodeController更改为this.parser。这在特定的代码行中不会发生。直到这里,转换才真正发生:
this.didStartCallback(this);
其中,本例中的this
是EpicodeParser,在运行此代码时,您已经将parserIdStart命名为didStartCallback。当你在这里用这个代码调用didStartCallback时,你本质上是在说。。。
didStartCallback.call(this,this(;
通过这样说.ddStartCallback((,您将其this
设置为..嗯。。当你叫它this
时。
您应该知道一个名为bind的函数,这里对此进行了解释:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
Bind从现有函数创建一个新函数,该函数的this
被固定(绑定(到您显式传递的任何对象。
中传递给didStartCallback
的this
EpisodeFeedParser.prototype.parse = function(doc){
this.didStartCallback(this);
类型为EpisodeFeedParser
在EpisodeController.prototype.fetchEpisodes
中影响EpisodeController.parserDidStart
到parser.didStartCallback
:
parser.didStartCallback = this.parserDidStart;
所以this.didStartCallback(this);
实际上是EpisodeController.parserDidStart(this)
并且我们在开始时看到最后一个CCD_ 23是CCD_。
Q.E.D.
尝试:
var that = this;
parser.didStartCallback = function(parser) {
that.parserDidStart(parser);
};
这将创建一个闭包,该闭包在正确的范围内传递给parserDidStart
。目前,当您调用this.parser.parse()
时,它会将EpisodeFeedParser
作为上下文传递,因为这是它的调用来源。这是JavaScript中作用域的一个怪癖,可能非常令人沮丧。
问题是"didStartCallBack"在"this"上(以及在的上下文中(被调用,在执行时"this"指的是EpisodeFeedParser。我已经用.call((修复了它,虽然我不确定为什么你需要如此迂回地编写代码,但我相信一定有原因。
重要变化:
parse: function(episodeController){
this.didStartCallback.call(episodeController, this);
}//parse
完整代码:
<html>
<head>
<script type="text/javascript">
//An interesting context problem...
//Why is it of type EpisodeFeedParser?
// ---- EpisodeFeedParser
var EpisodeFeedParser = function(url){
this.url = url;
};
EpisodeFeedParser.prototype = {
url:null,
didStartCallback:null,
parse: function(episodeController){
this.didStartCallback.call(episodeController, this);
}//parse
}//prototype
// ---- EpisodeController
var EpisodeController = function(){
this.episodes = new Array();
this.parser = null; //lazy
};
EpisodeController.prototype = {
parserDidStart: function(parser){
console.log("here *this* is not of type EpisodeController but it is EpisodeFeedParser Why?");
debugger;
this.testEpi(); //**********ERROR HERE!***********
},
fetchEpisodes: function(urlString){
if(urlString !== undefined){
if(this.parser === null){
this.parser = new EpisodeFeedParser(urlString);
this.parser.didStartCallback = this.parserDidStart;
}//if
this.parser.parse(this);
}//if
},//fetchEpisodes
testEpi: function(){
console.log("it worked!");
}
}//EpisodeController.prototype
// ---- Global Stuff
function testEpisode(){
var controller = new EpisodeController();
controller.fetchEpisodes("myurl");
}
</script>
</head>
<body>
<button type="button" onclick="testEpisode()">press me</button>
</body>
</html>
EpisodeFeedParser.prototype.parse = function(doc){
this.didStartCallback(this);
};
我不明白你为什么期望this
是EpisodeFeedParser
以外的任何东西。
- 为什么不't Javascript对我的输入值进行了一些重新检查
- 为什么“;未定义的“;在JavaScript中结束循环
- 为什么这在IE中的工作方式与在Firefox中不同
- 知道为什么我的旋转木马不会自动更改图片吗
- 为什么会出现错误;未捕获的类型错误:undefined不是函数;
- 为什么在单独的函数中应用时转换会闪烁/断断续续(D3)
- 为什么在变形之前不缺少Fx
- 为什么JavaScript在for循环为3时向所有4发出警报
- 为什么不是't窗口.恢复正常工作吗?(javascript/jquery)
- 为什么Airbnb风格指南说不鼓励依赖函数名称推断
- 为什么要使用0>javascript中的0
- 为什么无法在TypeScript中导出类实例
- 为什么grunt contrib connect的中间件选项的第三个参数是未定义的
- 为什么我的d3.jsselectAll+过滤器没有过滤
- 为什么HTML5拖放的目标是孩子?(可排序列表)
- 为什么忽略了eval()代码中的语法错误
- 为什么在画布上画线;t出现
- 为什么js事件消失了
- 为什么元素的宽度在页面加载之后和那一刻之后不同
- 为什么不'在JQuery中找到第二个css选择器的工作