setInterval, this, again

只谈情不闲聊 提交于 2019-12-02 17:23:25

问题


I have a problem in regards to setInterval that i cant figure out.

i "know" (...) there is the problem with the scope when calling setInterval or timeout from within an object, but still i cant wrap my head around it.

I tried to put my stuff inside an anonymous function, it wont work.

This is basicly my problem, simplified to the bare bones:

function Scenario(){
    var ships = [];
    this.ini = function(){
        for (var i = 0; i < ships.length; i++){
            timeoutID1 = setTimeout(ships[i].ding, 1000);
            timeoutID2 = setTimeout(ships[i].bing, 1000);
        }
    }
    this.setShips = function(){
        var ship = new Ship("ship");
        ships.push(ship);    
    }        

    function Ship(name){
        this.name = name;
        this.ding = function(){
            intervalID1 = setInterval(function(){
                console.log("ding");
            }, 500)      
        }
        this.bing = function(){
            var _this = this;
            intervalID2 = setInterval(function(){
                console.log(_this.name);
            }, 500)      
        }
    }
    this.setShips();
}


var scenario = new Scenario();
scenario.ini();

http://jsfiddle.net/ancientsion/xkwsn7xd/

Basicly, console.log("ding") works, console.log(_this.name) doesnt.

Why ?


回答1:


By the time setTimeout() gets around to call your method, it only sees the function and not the invocation context (i.e. the object to bind it to); much like this:

var bing = ships[i].bing;

bing(); // inside bing(), this == window

Basically, you need to provide setTimeout() with a prewired method invocation:

var bound_bing = ships[i].bing.bind(ships[i]);
timeoutID2 = setTimeout(bound_bing, 1000);

The "magic" happens with .bind() as it returns a new function that will have this set up properly.




回答2:


This is your problem simplified to bare bones:

var ship = {
    name: 'Sheep',
    ding: function() {
        console.log(this.name);
    }
}

setTimeout(ship.ding, 1000); // doesn't work correctly

It may help to see another example to understand why the above doesn't work:

var ding = ship.ding;
ding(); // doesn't work either

In JavaScript this depends on how you call your function. ship.ding() will set this to the sheep object. Bare ding() call will set this to the window object.

You can bind the function to the object you want by using .bind() method. (Function.prototype.bind())

var ding = ship.ding.bind(ship);
ding(); // works

ding is now permanently bound to the sheep object. You can use exactly the same approach with setTimeout:

setTimeout(ship.ding.bind(ship), 1000);



回答3:


You should define the value _this in Ship function:

function Ship(name){
    this.name = name;
    this.ding = function(){
        intervalID1 = setInterval(function(){
            console.log("ding");
        }, 500)      
    }
    var _this = this;
    this.bing = function(){
        intervalID2 = setInterval(function(){
            console.log(_this.name);
        }, 500)      
    }
}



回答4:


Hoist _this out of the bing function.

you should have

_this = this,
this.bing = function() {
            intervalID2 = setInterval(function(){
                console.log(_this.name);
            }, 500)   
}  

Javascript is imperative so you need to follow the execution path carefully. In function Ship, this points to a Ship object, in function bing, this points to the global scope (window). You need to save a reference to this so that you can refer back to it in these types of functions.




回答5:


You put ships[i].bing in setTimeout turns out that the caller of bing is not ships[i] but global, so _this is pointing to global actually.



来源:https://stackoverflow.com/questions/27570546/setinterval-this-again

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!