84669 person learning
152542 person learning
20005 person learning
5487 person learning
7821 person learning
359900 person learning
3350 person learning
180660 person learning
48569 person learning
18603 person learning
40936 person learning
1549 person learning
1183 person learning
32909 person learning
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