4

看来我不能在函数this内部使用setInerval。这是为什么?什么是优雅的解决方案?

<html>
<script>
var something = function(tMessage){
    this.message = tMessage;
};

something.prototype = {
    start : function(counter){
       document.getElementById('result').innerHTML += this.message + "+++<br />";
        var looper = setInterval(
            function(){
                // This is printing "undefined"
                document.getElementById('result').innerHTML += this.message + "<br />";
                if(!counter--)
                    clearInterval(looper);
            },
            20
        );
    }
};


window.onload = function(){
    var e = new something("hi");
    e.start(2);
}
</script>
<body>
<div id="result"></div>
</body>
</html>

编辑

感谢您的回答!但是谁能解释发送参数和设置以及额外变量之间的区别?有内存问题吗?

4

4 回答 4

6

这里的问题是当你的函数被调用时this是指全局对象。要保留当前范围,您可以关闭:

    var looper = setInterval(
        (function(scope){
            return function(){
                // This will no longer be printing "undefined"
                document.getElementById('result').innerHTML += scope.message + "<br />";
                if(!counter--)
                    clearInterval(looper);
            };
         })(this),
        20
    );

而不是挥手并试图解释闭包(我仍在完全掌握的过程中),我将引导您找到这个出色的答案:https ://stackoverflow.com/a/111200/1726343

于 2012-11-17T12:34:46.727 回答
4

您不能使用this,因为您在一个新的功能块中。我总是创建一个局部变量(我确信有更好的方法):

var c = this;
setInterval(function(
   c.variable = 1;
), 100);
于 2012-11-17T12:32:46.663 回答
1

因为问题被标记为 [prototypejs] 但没有一个答案使用 Prototype,所以我决定写一个真正使用 Prototype ( jsfiddle ) 的答案。

var Something = Class.create({
    initialize: function(tMessage) {
        this.message = tMessage;
    },

    start: function(counter) {
        this.counter = counter;
        $("result").innerHTML += this.message + "+++<br />";
        this.looper = setInterval(this.addMessage.bind(this), 20);
    },

    addMessage: function() {
        $("result").innerHTML += this.message + "<br />";
        if (!this.counter--) {
            clearInterval(this.looper);
        }
    }
});

document.observe("dom:loaded", function() {
    var e = new Something("hi");
    e.start(2);
});
  1. 使用Class.create()创建更优雅的类。
  2. 使用$()而不是document.getElementById().
  3. 使用document.observe("dom:loaded")代替window.onload
  4. 使用bind(this)将函数绑定到上下文。

问题的关键在于函数的执行上下文。无论你在哪里使用this,它都只是指向当前的执行上下文。当您调用someObject.someFunction()thensomeFunction()时,在 的上下文中执行someObject,并且this在 的内部someFunction()将指向someObject.

但是你可以先赋值someOtherObject.someFunction = someObject.someFunction,然后在someOtherObject.someFunction() this会中指向someOtherObject

您也可以将函数的引用传递给另一个函数,就像在 中所做的那样setInterval(),然后执行上下文将由setInterval()(实际上它将是全局上下文,即this===window)定义。

为了将执行上下文绑定到函数(预定义上下文,覆盖调用者的上下文),您需要使用.bind()method. 它返回新函数,无论运行时哪个上下文都将使用您所需的上下文调用您的原始函数。

于 2012-11-20T08:10:26.447 回答
0

添加

var self = this;

就在您调用 setInterval 之前,在 set*interval 中定义的函数中使用 self 而不是 this

于 2012-11-17T12:43:32.357 回答