Javascript 为什么*这个*不是*这个*?
我只是写了这段代码来表示这个正在杀死我的错误(Grrr!) 我想知道为什么当我得到error:methodundefined时,我在Safari中检查过,parserDidStart()方法中的这个变量不是EpisodeController类型,而是EpisodeFeedParser类型为什么Javascript 为什么*这个*不是*这个*?,javascript,scope,this,Javascript,Scope,This,我只是写了这段代码来表示这个正在杀死我的错误(Grrr!) 我想知道为什么当我得到error:methodundefined时,我在Safari中检查过,parserDidStart()方法中的这个变量不是EpisodeController类型,而是EpisodeFeedParser类型为什么 <html> <head> <script type="text/javascript"> var EpisodeFeedParser = function(url){
<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>
var eposodefeedparser=函数(url){
this.url=url;
this.didStartCallback=null;
};
eposodefeedparser.prototype.parse=函数(doc){
this.didStartCallback(this);
};
var eposodecontroller=函数(){
this.scents=新数组();
this.parser=null;//懒惰
};
eposodecontroller.prototype.parserDidStart=函数(解析器){
log(“这里*这*不是EpisodeController类型,但它是EpisodeFeedParser为什么?”);
这里是this.testEpi();//**********错误***********
};
EpisodeController.prototype.FetchSpidences=函数(urlString){
if(urlString!==未定义){
if(解析器===未定义){
var parser=新的eposodefeedparser(urlString);
parser.didStartCallback=this.parserDidStart;
this.parser=解析器;
}
this.parser.parse();
}
};
eposodecontroller.prototype.testEpi=函数(){
log(“它工作了!”);
};
函数testEpisode(){
var controller=新的eposodecontroller();
controller.fetch(“myurl”);
}
按我
此
在中传递给didStartCallback
EpisodeFeedParser.prototype.parse = function(doc){
this.didStartCallback(this);
属于类型eposodefeedparser
在eposodecontroller.prototype.fetchSpices
中,您将影响eposodecontroller.parserDidStart
到parser.didStartCallback
:
parser.didStartCallback = this.parserDidStart;
所以this.didStartCallback(this)
实际上是eposodecontroller.parserDidStart(this)
我们一开始就看到最后一个这个是eposodefeedparser
类型
Q.E.D
我不明白你为什么期望这个不是一个eposodefeedparser
试试:
var that = this;
parser.didStartCallback = function(parser) {
that.parserDidStart(parser);
};
这将创建一个在正确范围内传递到parserDidStart
的闭包。当前,当您调用this.parser.parse()
时,它会将eposodefeedparser
作为上下文传递,因为它是从上下文调用的。这是JavaScript中作用域的一个怪癖,可能会非常令人沮丧。问题是,在执行的某个点上,当“this”指的是eposodefeedparser时,“didStartCallBack”被调用(在“this”的上下文中)。我已经用.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>
//一个有趣的上下文问题。。。
//为什么它是eposodefeedparser类型?
//----情节分析器
var eposodefeedparser=函数(url){
this.url=url;
};
eposodefeedparser.prototype={
url:null,
didStartCallback:null,
解析:函数(场景控制器){
this.didStartCallback.call(eposodecontroller,this);
}//解析
}//原型
//----情节控制器
var eposodecontroller=函数(){
this.scents=新数组();
this.parser=null;//懒惰
};
eposodecontroller.prototype={
parserDidStart:函数(解析器){
log(“这里*这*不是EpisodeController类型,但它是EpisodeFeedParser为什么?”);
调试器;
这里是this.testEpi();//**********错误***********
},
函数(urlString){
if(urlString!==未定义){
if(this.parser==null){
this.parser=new eposodefeedparser(urlString);
this.parser.didStartCallback=this.parserDidStart;
}//如果
this.parser.parse(this);
}//如果
},//每集
testEpi:function(){
log(“它工作了!”);
}
}//幕式原型
//----全球的东西
函数testEpisode(){
var controller=新的eposodecontroller();
controller.fetch(“myurl”);
}
按我
这是Javascript经常被误解的一个方面。(我所说的“this”是指this
)
您可以将此
视为另一个不可见地传递到函数中的参数。所以当你写一个函数,比如
function add (a,b) {
return a+b;
}
你真的在写作
function add(this, a, b) {
return a+b;
}
这一点很可能是显而易见的,而不明显的恰恰是传递进来的,并被命名为“this”。这方面的规则如下。调用函数有四种方法,每种方法都将不同的东西绑定到this
经典函数调用
在经典函数调用中,此
绑定到全局对象。这条规则现在被普遍认为是一个错误,在未来的版本中可能会设置为null
构造函数调用
在构造函数调用中,此
被设置为一个新对象,其内部(且不可访问)原型指针被设置为add.prototype
方法调用
在方法调用中,this
被设置为someobject。最初在何处定义add并不重要,无论它是在构造函数内部、特定对象原型的一部分,还是其他什么。如果以这种方式调用函数,this
将设置为调用它的任何对象。这是你正在违反的规则
调用/应用调用
在call/apply调用中,这个
被设置为传入call方法现在可见的第一个参数的值
代码中发生的情况如下:
this.parser.didStartCallback = this.parserDidStart;
当您编写parserDidStart时,希望在方法调用它时,它的this
将是一个脚本控制器。。。实际上,您现在正在将其this
从eposodecontroller更改为this.parser。那是不可能的
add(a,b);
new add(a,b);
someobject.add(a,b);
add.call(someobject,a,b);
this.parser.didStartCallback = this.parserDidStart;
this.didStartCallback(this);