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
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你猜对了。
Aaa {a:12}
setInterval
最大的问题来源是,JS是个脚本语言,定义是定义,执行是执行,对于函数更是如此,你作了函数的定义或当值来传递,并不代表它一定在执行时不会因此改变,this值就是有可能改变结果的变因。
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,1000);
this.a
setInterval(this.show.bind(this),1000);
下面题外话,只是撰写调试的小建议供参考。
第1是为什么要用同样的变量名称?这例子里出现了二个a变量,一个在函数里,一个在外面(全局),英文字元有26个,再加上可以大小写与各种长短不一的组合,一定要用同样的变量名称,是要考验自己还是考验来看代码的人?在show函数中到底是想要输出函数中的a,还是外面的对象a?
第二是为什么在调试时要用setInterval而不用setTimeout,这两个不是类似的功用,差异是setTimeout只执行一次而已。问我说这么讲究作什么?问题是setInterval是一直执行下去,同样的代码你执行一次看到结果不对,难道第二次有可能变正确?而且这在调试时非常不便,我如果把代码贴到主控台测,它一直执行不停,不就又要想办法先关掉它再作第二次修正再执行。
setTimeout
我都要先改写过代码如下才能调试:
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。
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值,你可以记住它或直接把原来的输出语句改写。
目前我知道有三种解决的方案,以下列出来:
bind
setInterval(this.show.bind(this), 1000);
that
that.show
//最后一个传入this进去 setInterval(function(that){that.show();}, 1000, this);
注: that随便变量名,有人也用self或_that等等
self
_that
that.show()
this.show()
(function (that){ setInterval(function(){that.show();}, 1000); })(this);
以上,算补充内容,有兴趣可以套用试试。
当执行到 new Aaa()时,function Aaa中的this就已经绑定成新创建的object了。
new Aaa()
function Aaa
object
function Aaa(){ this.a = 12; setInterval(this.show.bind(this),1000); }
可以绑定 this
this指的是,调用函数的那个对象
Javascript的this用法
setInterval里的函数this指向window,没错,这也正是打印a对象的原因;
a
调用了a对象(其实是原型)的show方法,这也没错,因为在Aaa里你给setInterval传的this就是a对象;
show
Aaa
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
//注意下面两个this的不同就好了 setInterval(this.show, 1000) setInterval(function(){ this.show(); }, 1000);
setInterval里面的this指向的是window对象。
准确说应该是setInterval第一个回调函数运行时,内部上下文this, 而不是传参时那个this。
更正一下其中的错误,
回答这个问题,只用个二三句话是很难回答得清楚,要用旁敲侧击的讲法,说实在都有点对又不太对。
我猜想你应该是想要打印12的结果,而不是现在的
Aaa {a:12}
这个结果。问题在于setInterval
你猜对了。最大的问题来源是,JS是个脚本语言,定义是定义,执行是执行,对于函数更是如此,你作了函数的定义或当值来传递,并不代表它一定在执行时不会因此改变,
this
值就是有可能改变结果的变因。这段代码会怎么执行?顺序又是什么,大致上模拟一下:
呃,上面看完了。那如何让
setInterval(this.show,1000);
在执行时能打印出this.a
的值,说起来简单,改成像下面这样就行了,但为何能这样作,说起来也是满大一串的:下面题外话,只是撰写调试的小建议供参考。
第1是为什么要用同样的变量名称?这例子里出现了二个a变量,一个在函数里,一个在外面(全局),英文字元有26个,再加上可以大小写与各种长短不一的组合,一定要用同样的变量名称,是要考验自己还是考验来看代码的人?在show函数中到底是想要输出函数中的a,还是外面的对象a?
第二是为什么在调试时要用
setInterval
而不用setTimeout
,这两个不是类似的功用,差异是setTimeout
只执行一次而已。问我说这么讲究作什么?问题是setInterval
是一直执行下去,同样的代码你执行一次看到结果不对,难道第二次有可能变正确?而且这在调试时非常不便,我如果把代码贴到主控台测,它一直执行不停,不就又要想办法先关掉它再作第二次修正再执行。我都要先改写过代码如下才能调试:
补充说明
setInterval
的第一个传入值,要是个回调函数,等到时间到要移回主执行线中执行的。回调函数,预设呼叫它的必是window
物件,也就是函数区块中的this
预设是window
。看到很多回答的人也误解了,顺便谈一下,下面这两个例子有何不同?
第1例在执行到这行时,实际会转变为下面这样,这才算函数:
在本题目中,最后的第1例与第2例的
this
值都是window
对象,所以分别要执行的是下面这两个,结果写后面注解:真正要解让
setInterval
能够是输出a对象中的a属性,只有一种途径,让传入的这个回调函数的this
值钉住,让它必定指到执行当下的对象,所谓的钉住主要是要取得在执行的那一时刻的this
值,你可以记住它或直接把原来的输出语句改写。目前我知道有三种解决的方案,以下列出来:
1. 用
bind
方法。这是个函数中自带的方法,可以用个物件来"绑定"某个函数后,回传一个新已绑定的函数。一般用这个方案,不过要习惯一下。2. 用
setInterval
的第三个传入参数值,把this
传入作为that
用,执行的是that.show
。注意这方式在IE9之前的浏览器版本不相容。3. IIFE解法,也是要传入
this
到IIFE中,与上面概念类似。IIFE一执行时就会固定住that
,这里是执行that.show()
,而不是有可能会变的this.show()
:以上,算补充内容,有兴趣可以套用试试。
当执行到
new Aaa()
时,function Aaa
中的this
就已经绑定成新创建的object
了。可以绑定 this
this指的是,调用函数的那个对象
Javascript的this用法
setInterval
里的函数this
指向window
,没错,这也正是打印a
对象的原因;调用了
a
对象(其实是原型)的show
方法,这也没错,因为在Aaa
里你给setInterval
传的this
就是a
对象;function Aaa(){
}
Aaa.prototype.show = function(){
}
var a = new Aaa();//这里a引用了新对象Aaa
执行new Aaa()后,构造函数以及原型上的this将指向a,
setInterval(this.show,1000)等同于setInterval(a.show,1000)
这个打印的就是window.a