Javascript 在setTimeout上更改匿名函数的作用域会导致奇怪的警告

Javascript 在setTimeout上更改匿名函数的作用域会导致奇怪的警告,javascript,scope,Javascript,Scope,这纯粹是因为我对研究和个人发展感兴趣。我有一组名称空间的函数/变量 在1个函数中,我需要通过setTimeout调用另一个函数,但要将作用域保持为“this”。我有点纠结于此,似乎无法在setTimeout运行时绑定它 var foo = { ads: ["foo","bar"], timeDelay: 3, loadAds: function() { var al = this.ads.length; if (!al)

这纯粹是因为我对研究和个人发展感兴趣。我有一组名称空间的函数/变量

在1个函数中,我需要通过setTimeout调用另一个函数,但要将作用域保持为“this”。我有点纠结于此,似乎无法在setTimeout运行时绑定它

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

        }
    };
};
有没有一种优雅的方式可以做到这一点?我知道我能做到

var _this = this;
并在anon回调中引用此。例如,在mootools中,我会使用
.bind(this)
代替


不,因为这涉及到动画,我不想在字符串周围使用
,因为它需要评估,并且会影响性能

据我所知,您确实应该使用以下内容:

var self = this;
setTimeout(function(){self.scrollAd(ad);}, this.timeDelay * 1000);
var self = this;
setTimeout(function(){
    function(){
    }.apply(self);
}, this.timeDelay * 1000);
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);
        }
    };
};
但如果您非常想使用
.apply()
,请按如下方式操作:

var self = this;
setTimeout(function(){self.scrollAd(ad);}, this.timeDelay * 1000);
var self = this;
setTimeout(function(){
    function(){
    }.apply(self);
}, this.timeDelay * 1000);
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);
        }
    };
};
还请注意,如果您在
for
循环中运行此函数,并在计时器中运行的函数中使用
i
的值,则函数将始终以
i
的最后一个值运行(即
i==al
)。为了解决这个问题,您需要分别对
i
的每个值进行闭包

因此,使用您的代码并使其正常工作应该如下所示:

var self = this;
setTimeout(function(){self.scrollAd(ad);}, this.timeDelay * 1000);
var self = this;
setTimeout(function(){
    function(){
    }.apply(self);
}, this.timeDelay * 1000);
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);
        }
    };
};
var foo={
广告:[“foo”,“bar”],
延时:3,
loadAds:function(){
函数runTimed(o、fn、args、time)
{
setTimeout(函数(){fn.apply(o,args);},time);
}
var al=此长度;
如果(!al)
return;//没有广告
对于(变量i=0;i
注意:我没有运行此代码,因此它可能包含一些错误

另外,如果我是您,我会使用对象中的数据,而不会将其传递给
scrollAd
I
就足够了)

但是,您可能更喜欢使用新的ECMAScript第五版函数绑定功能,该功能具有更紧凑的语法:

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

for(var i=0;i.)

是的,很酷。这个.bind原型工作得很好,这正是我所需要的。呃,是的,我错过了迭代问题,恢复到使用forEach作为自定义原型迭代器。干杯好吧,看看