代码之家  ›  专栏  ›  技术社区  ›  Dimitar Christoff

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

  •  3
  • Dimitar Christoff  · 技术社区  · 15 年前

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

    .apply(这)确实会在console.log输出右对象时更改作用域,但它会立即运行该函数,然后在回调保持为空时出现异常/警告:

    useless setTimeout call (missing quotes around argument?)
    

    var _this = this;
    

    和参考 _this .bind(this)

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

    2 回复  |  直到 15 年前
        1
  •  9
  •   Community CDub    8 年前
    for(var i = 0; i < al; i++) {
        setTimeout(function() {
            this.scrollAd(this.ads[i]);
        }.apply(this), this.timeDelay * 1000);
    }
    

    apply 不绑定函数,而是调用它。因此,直接执行滚动,然后传递其返回值( undefined )到 setTimeout

    你可能想用这样的闭包 this 和循环变量(必须关闭,否则每次超时后循环值相同):

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

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

    (有一个 function.bind 对于本机不在浏览器底部的浏览器 this answer .)

        2
  •  2
  •   inkredibl    15 年前

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

    但是如果你非常想使用 .apply()

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

    还要注意,如果在 for i 的值,则您的函数将始终以的最后一个值运行 (即。 i == al ). 为了解决这个问题,您需要使用的每个值创建一个闭包

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

    注: 我没有运行此代码,因此它可能包含一些错误。

    scrollAd (

    推荐文章