Javascript 为什么*这个*不是*这个*?

Javascript 为什么*这个*不是*这个*?,javascript,scope,this,Javascript,Scope,This,我只是写了这段代码来表示这个正在杀死我的错误(Grrr!) 我想知道为什么当我得到error:methodundefined时,我在Safari中检查过,parserDidStart()方法中的这个变量不是EpisodeController类型,而是EpisodeFeedParser类型为什么 <html> <head> <script type="text/javascript"> var EpisodeFeedParser = function(url){

我只是写了这段代码来表示这个正在杀死我的错误(Grrr!)

我想知道为什么当我得到error:methodundefined时,我在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> 

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);