本篇文章针对一个面试题来了解 this ,重在过程
题目如下:
function Obj(msg){ this.msg = msg; this.shout = function(){ console.log(this.msg); } this.waitAndShout = function(){ // 要求: 隔五秒钟后执行上面的 shout 方法 }
}
1.如果直接加入的是setInterval()会是什么结果?
function Obj(msg){ this.msg = msg; this.shout = function(){ console.log(this.msg); } this.waitAndShout = function(){ // 隔五秒钟后执行上面的 shout 方法
setInterval(this.shout,5000); //思考1个问题 :能不能调到 shout()方法?
} }
//创建对象并调用
var aa=new Obj("aa");
aa.shout() //aa;
aa.waitAndShout() ; //发现隔 5 秒显示的是 undefined ,这说明调用到了 shout() 方法,
//那么为什么每次返回的都是 undefined ?
// 我们可以先推断下:1. msg 未定义,所以默认返回值就是 undefined;
// 2. 此 shout 非彼 shout
2.求证我们的2个推断
//推断1. msg 未定义,所以默认都是 undefined;
//推断2. 此 shout 非彼 shout
//由于第2个推断比较容易验证,就先来验证它
this.shout = function(){ console.log("123456"); //将这里改成一个常量,你会发现每隔 5 秒显示的是 123456 ,所以可以得出调用到的就是shout方法 }
//那么余下的问题就是:msg 未定义
//我们知道setInterval中的shout方法调用的是this.msg,那么问题就应该出在这个this上面
//知道的人会说是window,那么如何验证呢?改动部分代码如下:
this.waitAndShout = function(){ // 隔五秒钟后执行上面的 shout 方法 setInterval( function(){alert this} ,5000 ); //你会发现弹出的是DOMwindow,是window对象; }
//先证实下是msg的问题,做个小测试,在window中添加 msg 变量;
window.msg="这是window中的msg";//那么运行以后每隔5秒显示的就是“这是window中的msg”;
但是我们又不能通过这种方式来解决问题,原因如下:
1.污染了全局对象
2.这里只有一个msg,如果说还有很多其他的东西呢
3.如果你再new一个对象 var bb = new Obj();那么 bb.waitAndShout 的 msg 和 aa.waitAndShout 的 msg 就是一样的,都是window.msg;
综上:解决办法就是 在一个函数自执行内部来改变上下文环境
最终代码如下
function Obj(msg){ this.msg = msg; this.shout = function(){ console.log(this.msg); } this.waitAndShout = function(){ // 隔五秒钟后执行上面的 shout 方法 var tmp=function(fn,obj){ return function(){ fn.call(obj); //改变执行上下文为obj,那么setInterval中就是Obj调用shout,当然也就能输出正确的 msg 了 } }(this.shout,this);
setInterval(tmp ,5000 );//至于clearInterval就自己解决吧
} } var aa=new Obj('aa'); aa.shout();//aa aa.waitAndShout(); var bb=new Obj('bb'); bb.waitAndShout();