admin管理员组文章数量:1279182
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 es 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...
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 es 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...
- OK just see stackoverflow./questions/18224847/… – AKZ Commented Oct 12, 2013 at 11:32
2 Answers
Reset to default 9for(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 pact 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).
版权声明:本文标题:javascript - changing the scope of an anonymous function on a setTimeout causes a weird warning - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741278230a2369856.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论