不能在setInterval中使用'this'

时间:2012-11-17 12:30:15

标签: javascript prototype

似乎我无法在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 个答案:

答案 0 :(得分: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
    );

我会引导您找到这个优秀的答案,而不是手工操作并尝试解释闭包({我3}}

答案 1 :(得分:2)

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

var c = this;
setInterval(function(
   c.variable = 1;
), 100);

答案 2 :(得分: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)将函数绑定到上下文。
  5. 问题的关键在于功能的执行上下文。无论您在何处使用this,它都只指向当前的执行上下文。当您调用someObject.someFunction()时,someFunction()将在someObject的上下文中执行,this内的someFunction()将指向someObject

    但您可以进行作业someOtherObject.someFunction = someObject.someFunction,然后在someOtherObject.someFunction() this中指向someOtherObject

    此外,您可以将函数的引用传递给另一个函数,就像在setInterval()中一样,然后执行上下文将由setInterval()定义(实际上它将是全局上下文,即{{1} })。

    为了将执行上下文绑定到函数(预定义上下文,覆盖调用者的上下文),您需要使用this===window方法。它返回新函数,无论运行时的上下文是什么,它都将使用您想要的上下文调用原始函数。

答案 3 :(得分:0)

添加

var self = this;

在调用setInterval之前,使用self而不是this到set * interval

中定义的函数