如何将数据传递给JavaScript中的匿名函数?

时间:2009-05-24 14:40:16

标签: javascript closures

当我将'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语句放在另一个函数中使它全部工作:

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

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

对于令人困惑和冗长的帖子感到抱歉。

3 个答案:

答案 0 :(得分:5)

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

  1. 常规函数调用
    myFunc(param1, param2);
    这种调用函数的方法总是将“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”被初始化为一个新对象,该对象从函数的prototype属性继承方法和属性。在这种情况下,新对象将继承自MyConstructor.prototype。此外,如果您未明确返回值,则会返回“this”。
  5. 您使用的解决方案是推荐的解决方案 - 将“this”的外部值分配给另一个在您的函数内仍然可见的变量。我唯一要改变的是将变量称为“那个”,如TörökGábor所说 - 这是事实上的标准,可能会让你的代码更容易为其他程序员阅读。

答案 1 :(得分:3)

你对闭包感到困惑。

对于第一个问题,是的,你是对的,就是这样做的方式。唯一的区别是有一个约定来命名保存that的变量this

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

在StackOverflow上已有一个很好的线程。检查问题 How does a javascript closure work?的答案。

您的第二个问题与Javascript closure inside loops - simple practical example完全相同。

答案 2 :(得分:0)

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

像那样:

$.getJSON("answer.html",{},(function(me){return function(data){me.gotAnswer(count);}})(this));