closures - How is data passed to anonymous functions in JavaScript? - Stack Overflow

When I pass 'this' to an anonymous function like so:MyClass.prototype.trigger = function(){wi

When I pass 'this' to an anonymous function like so:

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

I get a "this.onTimeout is not a function"-error. I guess that 'this' is no longer available at the time the anonymous function is executing? So I've been doing this:

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

Is this really how you're supposed to do things? It kinda works, but it feels weird.

Then we have this example:

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

});

This outputs:

2
2

Shouldn't it output:

1
2

instead? Then I discovered that putting the $.getJSON-statement in another function makes it all work:

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

This outputs:

1
2

(Or the other way around.) What's happening here? What is the right way to pass variables to an anonnymous function?

Sorry for the confusing and lengthy post.

When I pass 'this' to an anonymous function like so:

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

I get a "this.onTimeout is not a function"-error. I guess that 'this' is no longer available at the time the anonymous function is executing? So I've been doing this:

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

Is this really how you're supposed to do things? It kinda works, but it feels weird.

Then we have this example:

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

});

This outputs:

2
2

Shouldn't it output:

1
2

instead? Then I discovered that putting the $.getJSON-statement in another function makes it all work:

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

This outputs:

1
2

(Or the other way around.) What's happening here? What is the right way to pass variables to an anonnymous function?

Sorry for the confusing and lengthy post.

Share Improve this question edited Feb 19, 2014 at 10:30 BenMorel 36.7k52 gold badges206 silver badges337 bronze badges asked May 24, 2009 at 14:40 0scar0scar 3,20026 silver badges28 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 5

What you are experiencing is the correct behavior - it's not a good behavior, but it's part of the language. The value of "this" is reset inside every function definition. There are four ways to call a function that have different ways of setting "this".

  1. The regular function invocation
    myFunc(param1, param2);
    This way of calling a function will always reset "this" to the global object. That's what's happening in your case.
  2. Calling it as a method
    myObj.myFunc(param1, param2);
    This unsurprisingly sets "this" to whatever object the method is being called on. Here, "this" == "myObj".
  3. Apply method invocation
    myFunc.apply(myObj, [param1, param2])
    This is an interesting one - here "this" is set to the object you pass as the first parameter to the apply method - it's like calling a method on an object that does not have that method (be careful that the function is written to be called this way). All functions by default have the apply method.
  4. As a constructor (with "new")
    myNewObj = new MyConstructor(param1, param2);
    When you call a function this way, "this" is initialized to a new object that inherits methods and properties from your function's prototype property. In this case, the new object would inherit from MyConstructor.prototype. In addition, if you don't return a value explicitly, "this" will be returned.

The solution you used is the remended solution - assign the outside value of "this" to another variable that will still be visible inside your function. The only thing I would change is to call the variable "that" as Török Gábor says - that's sort of the de-facto standard and might make your code easier to read for other programmers.

You are confused about the closures.

For the first problem, yes, you are right, that is the way it can be done. The only difference that there is a convention to name the variable that that holds this.

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

There is already a nice thread about this on StackOverflow. Check answers for question How does a javascript closure work?.

Your second problem is an exact duplicate of Javascript closure inside loops - simple practical example.

you will have the same problem if inside your new method: newRequest you have to use a "for" or a "while" statement. Another solution could be creating a closure:

like that:

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

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744224864a4563956.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信