使用“this”在JavaScript类中的setTimeout()

时间:2011-05-06 12:11:00

标签: javascript oop closures

我试图在JavaScript中的类函数中使用setTimeout()setTimeout()应该在同一个类中触发另一个方法,因此我传递它的函数被写为window.setTimeout("this.anotherMethod", 4000)。这带来了问题:this引用了调用对象,在setTimeout()的情况下它是window。如何使用附件返回对类对象本身的引用?

myObject = function(){

this.move = function(){
    alert(this + " is running");
}
this.turn = function(){
    alert(this + " is turning");
}
this.wait = function(){
    window.setTimeout("this.run" ,(1000 * randomNumber(1,5)));
}

this.run = function(){
    switch(randomNumber(0,2)){
        case 0:
            this.move();
        break;
        case 1:
            this.turn();
        break;
        case 2:
            this.wait();
    }
}

}

14 个答案:

答案 0 :(得分:63)

你可以这样做:

 var that = this;
 setTimeout(function () {
     that.doStuff();
 }, 4000);

您还可以bind获取更简洁的代码(正如@Raynos最初指出的那样):

setTimeout(this.doStuff.bind(this), 4000);

bind是一个标准的库函数,用于完全符合这种编码模式(即从词法上捕获this)。

答案 1 :(得分:7)

您还可以将函数绑定到范围。

setTimeout(this.run.bind(this) ,(1000 * randomNumber(1,5)));

警告Function.prototype.bind是ES5

答案 2 :(得分:5)

正如您所发现的,

this在javascript中可能会出现问题。

我通常通过在对象中使用this别名来解决这个问题,这样每当我需要一个引用回到包含对象时我就可以使用别名。

MyObject = function ()
{
    var self = this;

    // The rest of the code goes here

    self.wait = function(){
        window.setTimeout(self.run ,(1000 * randomNumber(1,5)));
    }
}

答案 3 :(得分:3)

this.wait = function(){
    var self = this;
    window.setTimeout(function() { self.run() } ,(1000 * randomNumber(1,5)));
}

所以你将对你正在调用的对象的引用存储在局部变量('self')中。

答案 4 :(得分:2)

this对调用它的上下文很敏感。当您将字符串传递给setTimeout时,那就是eval在完全不同的背景下。

您需要保留this的当前值(通过将其复制到另一个变量)并维护范围(不使用(隐含)eval)。

this.wait = function(){
    var self = this;
    setTimeout(function () { self.run() },
              (1000 * randomNumber(1,5))
              );
}

答案 5 :(得分:2)

在主myObject的顶部,对this的当前值进行新的引用:

var self = this;

然后为您的计时器回调创建一个闭包,该闭包使用该新引用而不是setTimeout将用作回调中的默认上下文的全局对象:

setTimeout(function() {
    self.run();
}, 4000);

答案 6 :(得分:2)

var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);

func内,this始终引用全局对象。你可以将当前对象传入func,

var timeoutID = window.setTimeout(func, delay, this);
function func(that) {...}

不幸的是它在IE中不起作用

Note that passing additional parameters to the function in the first syntax does not work in Internet Explorer.

答案 7 :(得分:2)

class A{

   setTimeout(()=>{

       // here this != undefined because of arrow function

  },500);

}

答案 8 :(得分:1)

你有没有尝试过;

window.setTimeout("myObject.run" ,(1000 * randomNumber(1,5)));

答案 9 :(得分:1)

您可以只使用箭头函数语法:

setTimeout(() => {
     this.doStuff();
 }, 4000);

答案 10 :(得分:0)

您可以使用此代码,该代码适用于所有现代浏览器 -

setTimeout(function(thisObj) {thisObj.run();},1000,this);

参考:http://klevo.sk/javascript/javascripts-settimeout-and-how-to-use-it-with-your-methods/

答案 11 :(得分:0)

缩短方式。没有匿名功能。

body
{
background-color: #aaaaaa;
margin: 0px;
}

#page
{
margin: auto;
width: 940px;
background-color: #95bfca;
background-image: linear-gradient(left top, rgb(208,226,231) 0%, rgb(0,102,128) 80%);
background-image: -o-linear-gradient(left top, rgb(208,226,231) 0%, rgb(0,102,128) 80%);
background-image: -moz-linear-gradient(left top, rgb(208,226,231) 0%, rgb(0,102,128) 80%);
background-image: -webkit-linear-gradient(left top, rgb(208,226,231) 0%, rgb(0,102,128) 80%);
background-image: -ms-linear-gradient(left top, rgb(208,226,231) 0%, rgb(0,102,128) 80%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#d0e2e7', endColorstr='#006680', GradientType=0 );
}

#banner
{
margin: auto;
width: 936px;
height: 122px;
background-image: url("banner.jpg");
}

#tagline
{
margin: 10px;
padding: 10px;
border: 2px solid #783201;
font: italic 22px calibri, sans-serif;
text-align: center;
background-color: #fff5db;
}

#main
{
padding: 20px 15px;
overflow: hidden;
position: relative;
}

.mainelement
{
background-color: #fff5db;
border: 2px solid #783201;
padding: 10px;
}

#main h1
{
margin: 20px 0px;
font-weight: bold;
font-style: italic;
font-family: calibri, sans-serif;
font-size: 15px;
}

#main div p, #main div li
{
font: 15px calibri, sans-serif;
}

#main a
{
font: 15px calibri, sans-serif;
color: #783201;
}

#main .expandable
{
text-align: center;
padding-left: 5px;
background-image: url("expand.png");
background-repeat: no-repeat;
background-position: left center;
}

.underline
{
text-decoration: underline;
}

.italic
{
font-style: italic;
}

.inlineh1
{
font: italic bold 15px calibri, sans-serif;
}

#languagebar
{
margin: 20px 15px;
width: 100px;
float: left;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}

.flag
{
margin: 5px;
border: none;
}

#french
{
background-image: url("French.png");
float: left;
}

#english
{
background-image: url("English.png");
float: right;
}

#content
{
width: 700px;
float: right;
}

#footer
{
margin: auto;
font: 12px calibri, sans-serif;
color: #ffffff;
text-align: center;
}

#footer a
{
font: 12px calibri, sans-serif;
color: #ffffff;  
}

/*** menu ***/

#menu
{
background-color: #783201;
border-top: 3px solid #783201;
border-bottom: 3px solid #783201;
}

#innermenu
{
border-top: 1px solid #ffffff;
border-bottom: 1px solid #ffffff;
overflow: hidden;
}

.menuitem
{
float: left;
margin: 5px 33px;
padding-bottom: 10px;
background-image: url("menutwiddle.png");
background-repeat: no-repeat;
background-position: center bottom;
}

.menuitem a
{
font: 18px calibri, sans-serif;  
color: #ffffff;
text-decoration: none;
}

.activeitem
{
    background: url('menu-line.png') repeat-x bottom left;
    position: relative;
}

.activeitem:before
{
    position: absolute;
    top: 0;
    left: -6px;
    bottom: 0;
    width: 6px;
    content: ' ';
    background: url('menu-ball.png') no-repeat bottom left;
}

.activeitem:after
{
    position: absolute;
    top: 0;
    right: -6px;
    bottom: 0;
    width: 6px;
    content: ' ';
    background: url('menu-ball.png') no-repeat bottom left;
}

/*** form ***/

input[type=text], textarea
{
    border: 1px solid #783201;
}

input[type=submit]
{
    padding: 5px 15px;
    background: #783201;
    border-radius: 5px 5px;
    color: #fff;
    border: 0;
    box-shadow: 1px 1px 2px #888;
}

input[type=submit]:active
{
    box-shadow: 0 0 0 #fff;
}

答案 12 :(得分:0)

建议不要使用字符串

来使用setTimeout或setInterval
setTimeout("myFunction()", 5000);

//this is the same as 

setTimeout(function(){ eval("myFunction()"); }, 5000)); //<-- eval == BAD

答案 13 :(得分:0)

进入更复杂的情况......类A有一个类型B的成员和一个调用setTimeout的方法,该方法调用类B上的方法。解决方法如下:

class A {
    constructor(b) {
        this.b = b;
    }
    setTimer(interval) {
        setTimeout(this.b.tick.bind(this.b), interval);
    }
}
class B {
    constructor(name){
        this.name = name;
        this.ele = window.document.getElementById('B');
    }
    tick() {
        console.log(this);
        this.ele.innerText += ' ' + this.name;
    }
}

在B.tick中将A.b绑定到此并且工作。

这是bindhttps://jsfiddle.net/jrme9hyh/

的小提琴

没有bind的人失败了:https://jsfiddle.net/2jde8tq3/