js settimeout与this

var Cat = function(name) {
    this.name = name;
}

Cat.prototype.miao = function() {
    console.log("miao miao miao");
    setTimeout(this.miao(), 1000);
}

var cat = new Cat("hahaha");
cat.miao();

上面代码有什么问题吗?
理应1秒调用一次miao()函数,,但是调用次数之多之快却导致了浏览器奔溃图片描述

阅读 5.6k
6 个回答

同意 斑驳光影 说的内容。
另外再补充一下,如果不用bind这个方法,直接写成

javascriptCat.prototype.miao = function() {
    console.log("miao miao miao");
    setTimeout(this.miao, 1000);
}

你会发现程序打出了 两个 miao miao miao 然后就停止了。
在解释这个问题前,我们首先把 setTimeout 方法写成这样:

javascriptsetTimeout(fn,ms);

在第一次调用 setTimeout(this.miao,1000) 中,这个 this,指代的是 Cat 构造函数 new 出来的实例。递归运行后,打印了第二个 miao miao miao后,调用 setTimeout(this.miao,1000) ,此时 this 相当于在上一个 setTimeoutfn 中调用了。因此指代的是全局变量 window, 它并没有 miao 方法,因此会报错。程序也就因此停止了。

简而言之,在 setTimeout(fn,ms) 中,fn 内部的 this指代 window,如果 fn 本身就是 this.method,这个 this就指代所运行时的环境变量。
e.g.

var obj1 = {
    method: function(){
                setTimeout(function(){
                    console.log(this);//window
                },1000);
            }
}         

var obj2 = {
    method: function(){
                setTimeout(this.miao//this 指代obj2
                ,1000);
            },
    miao:function(){
            console.log('miao miao miao')
    }   
} 

obj1.method();
obj2.method();
    var Cat = function(name) {
        this.name = name;
    }
    Cat.prototype.miao = function() {
        console.log("miao miao miao");
        var cat = new Cat("hahaha");
        setTimeout('cat.miao()', 1000);
    }

    var cat = new Cat("hahaha");
    cat.miao();

setTimeout的用法是:

setTimeout(function () {}, 1000); //or
setTimeout('func()', 1000);

而你的写法直接传入一下this.miao(),这样setTimeout是无效的,然而它会直接循环执行this.miao()

setTimeout 传入的是一个function,而你直接把function执行了。。。
也就是说,你在miao函数里面又调了miao,改成这么写就行了
刚才是this的指向问题,

setTimeout(this.miao.bind(this),1000);

其实你这个直接是递归建立了无数setTimeout
应该

var Cat = function(name) {
    this.name = name;
}

Cat.prototype.miao = function() {
    console.log("miao miao miao");
    var _this = this; // 保存this引用 可以用es5 的bind 等技巧,
    // 另外 setTimeout('cat.miao()', 1000); 这个属于绝对调用 就是为了绑定正确的this
    setTimeout(function(){
       _this.miao()
    }, 1000);
}

var cat = new Cat("hahaha");
cat.miao();

比较懒的做法也可以直接用 arguments.callee 替代递归函数本身。

javascriptvar Cat = function(name) {
    this.name = name;
}

Cat.prototype.miao = function() {
    console.log("miao miao miao");
    setTimeout(arguments.callee, 1000);
}

var cat = new Cat("hahaha");
cat.miao();

es6 es7 :: =>就会清晰多了
没必要为了以前的坑继续补,当然bind(this)也行

不过这里的问题是,你不知道引擎怎么执行的
你传一个 fn() 当参数,那么必然要执行fn才能知道return,所以他就一直执行咯.

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题