5

当我将“this”传递给这样的匿名函数时:

MyClass.prototype.trigger = function(){
    window.setTimeout(function(){this.onTimeout();},1000);
}

我收到“this.onTimeout 不是函数”错误。我猜想在匿名函数执行时“this”不再可用?所以我一直在这样做:

MyClass.prototype.trigger = function(){
    var me = this
    window.setTimeout(function(){me.onTimeout();},1000);
}

这真的是你应该做的事情吗?它有点工作,但感觉很奇怪。

然后我们有这个例子:

$(function(){
    function MyClass(){
        this.queue = new Array();
    }
    MyClass.prototype.gotAnswer = function(count){
        $('body').append("count:"+count+"<br/>");
    }
    MyClass.prototype.loadAll = function(){
        var count = 0;
        var item;
        while(item = this.queue.pop()){
            count++;
            var me = this;
            $.getJSON("answer.html",{},function(data){me.gotAnswer(count);});
        }
    }

    var o = new MyClass();
    o.queue.push(1);
    o.queue.push(2);
    o.loadAll();

});

这输出:

2
2

它不应该输出:

1
2

反而?然后我发现将 $.getJSON-statement 放在另一个函数中可以使它全部工作:

MyClass.prototype.loadAll = function(){
    var count = 0;
    var item;
    while(item = this.queue.pop()){
        count++;
        this.newRequest(count);
    }
}
MyClass.prototype.newRequest = function(count){
    var me = this;
    $.getJSON("answer.html",null,function(data){ me.gotAnswer(count); });
}

这输出:

1
2

(或相反。)这里发生了什么?将变量传递给匿名函数的正确方法是什么?

很抱歉这篇令人困惑和冗长的帖子。

4

3 回答 3

5

你正在经历的是正确的行为——这不是一个好的行为,但它是语言的一部分。“this”的值在每个函数定义中被重置。有四种方法可以调用具有不同设置“this”的函数。

  1. 常规函数调用
    我的函数(参数 1,参数 2);
    这种调用函数的方式总是会将“this”重置为全局对象。这就是你的情况。
  2. 将其称为方法
    myObj.myFunc(param1, param2);
    这毫不奇怪将“this”设置为调用该方法的任何对象。在这里,“this”==“myObj”。
  3. 应用方法调用
    myFunc.apply(myObj, [param1, param2])
    这是一个有趣的 - 这里“this”设置为您作为第一个参数传递给 apply 方法的对象 - 这就像在没有该方法的对象上调用一个方法(注意该函数被编写为这样称呼)。默认情况下,所有函数都有 apply 方法。
  4. 作为构造函数(带有“new”)
    myNewObj = new MyConstructor(param1, param2);
    当您以这种方式调用函数时,“this”被初始化为一个新对象,该对象从函数的原型属性继承方法和属性。在这种情况下,新对象将继承自 MyConstructor.prototype。此外,如果您没有显式返回值,则会返回“this”。

您使用的解决方案是推荐的解决方案 - 将“this”的外部值分配给另一个变量,该变量在您的函数中仍然可见。我唯一要改变的就是像 Török Gábor 所说的那样将变量称为“那个”——这是事实上的标准,可能会让你的代码更容易被其他程序员阅读。

于 2009-05-24T15:06:31.943 回答
3

您对关闭感到困惑。

对于第一个问题,是的,你是对的,这是可以做到的。唯一的区别是有一个约定来命名that持有的变量this

MyClass.prototype.trigger = function(){
    var that = this;
    window.setTimeout(function(){that.onTimeout();},1000);
}

在 StackOverflow 上已经有一个很好的线程。检查问题的答案 javascript 闭包如何工作?.

您的第二个问题是循环内的 Javascript 闭包的完全重复- 简单实用的示例。

于 2009-05-24T14:46:52.903 回答
0

如果在您的新方法中,您将遇到同样的问题:newRequest 您必须使用“for”或“while”语句。另一种解决方案可能是创建一个闭包:

像那样:

$.getJSON("answer.html",{},(function(me){return function(data){me.gotAnswer(count);}})(this));
于 2013-12-05T09:04:23.743 回答