English 中文(简体)
changing the scope of an anonymous function on a setTimeout causes a weird warning
原标题:

this has interested me purely as research and personal development. i have a namespaced set of functions / variables.

within 1 function I need to call another through setTimeout but keeping the scope to this . i am struggling with this a little, can t seem to bind it for when the setTimeout runs.

var foo = {
    ads: ["foo","bar"],
    timeDelay: 3,
    loadAds: function() {
        var al = this.ads.length;
            if (!al)
                return; // no ads

            for(var i = 0; i < al; i++) {
                setTimeout(function() {
                    this.scrollAd(this.ads[i]);
                }.apply(this), this.timeDelay * 1000);
            }
        },
        scrollAd: function(adBlock) {
            console.log(adBlock);

        }
    };
};

the .apply(this) DOES change the scope as the console.log outputs the right object back, but it runs the function immediately and then the exception/warning comes up as the callback remains empty:

useless setTimeout call (missing quotes around argument?)

is there an elegant way of doing this at all? i know i could do

var _this = this;

and reference _this in the anon callback. for example, in mootools i d use .bind(this) instead...

and no, as this involves animating, i don t want to use " " around the string as it will need to be eval d and would impact performance...

最佳回答
for(var i = 0; i < al; i++) {
    setTimeout(function() {
        this.scrollAd(this.ads[i]);
    }.apply(this), this.timeDelay * 1000);
}

apply doesn t bind a function, it calls it. So you execute the scroll straight away and then pass its return value (undefined) to setTimeout, which is ineffective.

You probably meant to use a closure like this over this and the loop variable (which must be closed or it will be the same, post-loop value for every timeout):

for(var i = 0; i < al; i++) {
    setTimeout(function(that, j) {
        return function() {
            that.scrollAd(that.ads[j]);
        };
    }(this, i), this.timeDelay * 1000);
}

However you may prefer to use the new ECMAScript Fifth Edition function binding feature, which has a much more compact syntax:

for (var i= 0; i<al; i++)
    setTimeout(this.scrollAd.bind(this, this.ads[i]), this.timeDelay*1000);

(There s an implementation of function.bind for browsers that don t have have it natively at the bottom of this answer.)

问题回答

From what I know you should indeed use something like this:

var self = this;
setTimeout(function(){self.scrollAd(ad);}, this.timeDelay * 1000);

But if you badly want to use .apply(), then do it like this:

var self = this;
setTimeout(function(){
    function(){
    }.apply(self);
}, this.timeDelay * 1000);

Also note that if you run this inside a for loop and use i s value inside a function that is run in timer, then your function will always run with the last value of i (i.e. i == al). In order to fix that, you ll need to make a closure with each value of i separately.

So taking your code and making it work it should look like this:

var foo = {
    ads: ["foo","bar"],
    timeDelay: 3,
    loadAds: function() {
        function runTimed(o, fn, args, time)
        {
            setTimeout(function(){ fn.apply(o, args); }, time);
        }
        var al = this.ads.length;
            if (!al)
                return; // no ads

            for(var i = 0; i < al; i++) {
                runTimed(this, this.scrollAd, this.ads[i], this.timeDelay*1000);
            }
        },
        scrollAd: function(adBlock) {
            console.log(adBlock);
        }
    };
};

Note: I haven t run this code so it may contain some mistakes.

Also if I were you, I d use the data from object and don t pass it to the scrollAd (i is enough).





相关问题
selected text in iframe

How to get a selected text inside a iframe. I my page i m having a iframe which is editable true. So how can i get the selected text in that iframe.

How to fire event handlers on the link using javascript

I would like to click a link in my page using javascript. I would like to Fire event handlers on the link without navigating. How can this be done? This has to work both in firefox and Internet ...

How to Add script codes before the </body> tag ASP.NET

Heres the problem, In Masterpage, the google analytics code were pasted before the end of body tag. In ASPX page, I need to generate a script (google addItem tracker) using codebehind ClientScript ...

Clipboard access using Javascript - sans Flash?

Is there a reliable way to access the client machine s clipboard using Javascript? I continue to run into permissions issues when attempting to do this. How does Google Docs do this? Do they use ...

javascript debugging question

I have a large javascript which I didn t write but I need to use it and I m slowely going trough it trying to figure out what does it do and how, I m using alert to print out what it does but now I ...

Parsing date like twitter

I ve made a little forum and I want parse the date on newest posts like twitter, you know "posted 40 minutes ago ","posted 1 hour ago"... What s the best way ? Thanx.

热门标签