问题描述
|
我只是写了这段代码来代表这个正在杀死我的错误(Grrr!)
我想知道为什么当我收到错误消息:方法未定义我已经在Safari中检查了并且parserDidStart()方法中的此变量不是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经常被误解的方面。 (“ \”代表“ mean1”)
您可以将ѭ1视为另一个参数,该参数会无形地传递给函数。因此,当您编写类似的函数时,
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);
在构造函数调用中,将``1''设置为一个新的新对象,该对象的内部(且不可访问)原型指针设置为add。
方法调用
someobject.add(a,b);
在方法调用中,将“ 1”设置为某个对象。最初定义add的位置,无论它是在构造函数内部,还是特定对象的原型的一部分,还是其他因素都无所谓。如果您以这种方式调用函数,则将“ 1”设置为调用它的任何对象。这是您违反的规则。
调用/应用调用
add.call(someobject,b);
在call / apply调用中,将ѭ1设置为您传递给call方法现在可见的第一个参数的任何内容。
您的代码中会发生以下情况:
this.parser.didStartCallback = this.parserDidStart;
在编写parserDidStart时,期望它的this
在方法调用时将是EpisodeController……实际上发生的是,您现在正在将其this
从EpisodeController更改为this.parser。在特定的代码行中不会发生这种情况。直到这里才实际发生切换:
this.didStartCallback(this);
这里的this
是EpisodeParser,并且在运行此代码时,您已经将parserDidStart分配给了didStartCallback。当您在此处使用此代码调用didStartCallback时,实际上是在说...
didStartCallback.call(this,this);
通过说this.didStartCallback(),您可以将其this
设置为.. well。
您应该意识到一个名为bind的函数,在这里进行解释:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
Bind从现有函数创建一个新函数,该函数的ѭ1固定(绑定)到您显式传递的任何对象。
,this
传给didStartCallback
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)
我们从一开始就看到最后一个this
的类型为EpisodeFeedParser
。
Q.E.D
,尝试:
var that = this;
parser.didStartCallback = function(parser) {
that.parserDidStart(parser);
};
这将创建一个将正确范围传递到parserDidStart
的闭包。当前,当您调用this.parser.parse()
时,它将传递EpisodeFeedParser
作为上下文,因为它是从那里调用的。这是JavaScript范围的怪癖之一,并且可能令人沮丧。
,问题在于,在执行过程中,当“ this \”引用EpisodeFeedParser时,正在“ this \”上调用“ didStartCallBack \”。我已经使用.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);
};
我不明白为什么您会期望ѭ1等于26ѭ。