javascript - setInterval里面this指向的是window,下面的函数怎么理解
ringa_lee
ringa_lee 2017-04-10 17:22:18
0
11
1383
function Aaa(){
    this.a = 12;
    setInterval(this.show,1000);
}
Aaa.prototype.show = function(){
    console.log(this.a);
}
var a = new Aaa();
    

按照理解window里没有show的方法,结果打印出来的是a对象,理解不了,求大神指点

ringa_lee
ringa_lee

ringa_lee

reply all(11)
巴扎黑

setInterval里面的this指向的是window对象。

准确说应该是setInterval第一个回调函数运行时,内部上下文this, 而不是传参时那个this。

// this指向当前上下文
setInterval(this.show, 1000)

// this指向window
setInterval(function(){
    this.show();
}, 1000);

更正一下其中的错误,

    setInterval(this.show, 1000) // 这个this指向当前上下文没问题
    // 等价于
    setInterval(function(){
        console.log(this.a); 
         //这里的this还是指向window 实际输出的是window.a 
         // 前面定义时var a = new Aaa()被误导了
         // 修改一下变量名 var aa = new Aaa(); 应该输出undefined;
    }, 1000)
伊谢尔伦

回答这个问题,只用个二三句话是很难回答得清楚,要用旁敲侧击的讲法,说实在都有点对又不太对。

我猜想你应该是想要打印12的结果,而不是现在的Aaa {a:12}这个结果。问题在于setInterval你猜对了。

最大的问题来源是,JS是个脚本语言,定义是定义,执行是执行,对于函数更是如此,你作了函数的定义或当值来传递,并不代表它一定在执行时不会因此改变,this值就是有可能改变结果的变因。

这段代码会怎么执行?顺序又是什么,大致上模拟一下:

到`Aaa.prototype.show`这行,prototype物件先指定show成员,其中内容为`function(){console.log(this.a)}`

到`var obj = new Aaa();`这行,读取Aaa()中函数定义,并把函数中定义的`this`自动指向到obj变量。

进入到Aaa()函数区块中,`this.a=12`,所以指定`obj.a=12`,连住原型链。

Aaa()函数区块中执行`setInterval(this.show,1000);`,`this.show`作为参数,相当于obj.show中的属性成员,obj中没有,往原型链上找,找到prototype物件中有,所以setInterval中相当于以下的指定:

`setInterval(function(){console.log(this.a)}, 1000)`

`setInterval`中的执行函数代码送到工作伫列去,等会主执行线完成后再回来执行上下文堆叠中执行。

Aaa()函数区块中执行毕,刚刚`setInterval`中的执行函数代码回来执行上下文堆叠。

执行`console.log(this.a)`,作用域于全局,this指向window,输出window.a,相当于`Aaa {a:12}`

之后,`setInterval`中执行函数代码重覆执行。

呃,上面看完了。那如何让setInterval(this.show,1000);在执行时能打印出this.a的值,说起来简单,改成像下面这样就行了,但为何能这样作,说起来也是满大一串的:

setInterval(this.show.bind(this),1000);

下面题外话,只是撰写调试的小建议供参考。

第1是为什么要用同样的变量名称?这例子里出现了二个a变量,一个在函数里,一个在外面(全局),英文字元有26个,再加上可以大小写与各种长短不一的组合,一定要用同样的变量名称,是要考验自己还是考验来看代码的人?在show函数中到底是想要输出函数中的a,还是外面的对象a?

第二是为什么在调试时要用setInterval而不用setTimeout,这两个不是类似的功用,差异是setTimeout只执行一次而已。问我说这么讲究作什么?问题是setInterval是一直执行下去,同样的代码你执行一次看到结果不对,难道第二次有可能变正确?而且这在调试时非常不便,我如果把代码贴到主控台测,它一直执行不停,不就又要想办法先关掉它再作第二次修正再执行。

我都要先改写过代码如下才能调试:

function Aaa(){
    this.a = 12;
    setTimeout(this.show,1000);
}
Aaa.prototype.show = function(){
    console.log(this.a);
}
var obj = new Aaa();

补充说明

setInterval的第一个传入值,要是个回调函数,等到时间到要移回主执行线中执行的。回调函数,预设呼叫它的必是window物件,也就是函数区块中的this预设是window

看到很多回答的人也误解了,顺便谈一下,下面这两个例子有何不同?

//第1例
setInterval(this.show, 1000);

//第2例
setInterval(function(){this.show();}, 1000);

第1例在执行到这行时,实际会转变为下面这样,这才算函数:

//第1例
setInterval(function(){console.log(this.a);}, 1000);

在本题目中,最后的第1例与第2例的this值都是window对象,所以分别要执行的是下面这两个,结果写后面注解:

//第1例
console.log(window.a); //Aaa {a:12}

//第2例
window.show(); //报错,因为show函数不存在(全局中没有)

真正要解让setInterval能够是输出a对象中的a属性,只有一种途径,让传入的这个回调函数的this值钉住,让它必定指到执行当下的对象,所谓的钉住主要是要取得在执行的那一时刻的this值,你可以记住它或直接把原来的输出语句改写。

目前我知道有三种解决的方案,以下列出来:

1. 用bind方法。这是个函数中自带的方法,可以用个物件来"绑定"某个函数后,回传一个新已绑定的函数。一般用这个方案,不过要习惯一下。

setInterval(this.show.bind(this), 1000);

2. 用setInterval的第三个传入参数值,把this传入作为that用,执行的是that.show。注意这方式在IE9之前的浏览器版本不相容。

//最后一个传入this进去
setInterval(function(that){that.show();}, 1000, this);

注: that随便变量名,有人也用self_that等等

3. IIFE解法,也是要传入this到IIFE中,与上面概念类似。IIFE一执行时就会固定住that,这里是执行that.show(),而不是有可能会变的this.show():

(function (that){
    setInterval(function(){that.show();}, 1000);
})(this);

注: that随便变量名,有人也用self_that等等

以上,算补充内容,有兴趣可以套用试试。

迷茫

当执行到 new Aaa()时,function Aaa中的this就已经绑定成新创建的object了。

伊谢尔伦
function Aaa(){
    this.a = 12;
    setInterval(this.show.bind(this),1000);
}

可以绑定 this

黄舟

this指的是,调用函数的那个对象

Javascript的this用法

黄舟
  • setInterval里的函数this指向window,没错,这也正是打印a对象的原因;

  • 调用了a对象(其实是原型)的show方法,这也没错,因为在Aaa里你给setInterval传的this就是a对象;

巴扎黑

function Aaa(){

this.a = 12;
setInterval(this.show,1000);//这里的this指向的是创建的新对象Aaa,所以调用了show方法

}
Aaa.prototype.show = function(){

console.log(this.a);//这里能this指的是window了,所以this.a就是你下面创建的全局a

}
var a = new Aaa();//这里a引用了新对象Aaa

伊谢尔伦

执行new Aaa()后,构造函数以及原型上的this将指向a,
setInterval(this.show,1000)等同于setInterval(a.show,1000)

左手右手慢动作

这个打印的就是window.a

Peter_Zhu
//注意下面两个this的不同就好了
setInterval(this.show, 1000)

setInterval(function(){
    this.show();
}, 1000);
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!