一、什么是this
js中的this实际上保存着代码的执行环境,关于js指向问题,有下面几种情况:
1.函数中的this总是指向调用它的对象,当没有明确的调用对象的时候this指向window(非严格模式下)(其实是js引擎调用的,也可以理解为是window调用的);
2.构造函数中的this指向构造函数的实例;
3.js事件回调函数里this指向dom节点对象;
4.使用apply、call、bind方法可以改变this的指向。
二、普通对象里的this
先看下面的例子
1 | function f(){ |
上面的例子中f、i都没有明确的调用对象(其实是引擎调用的,也可以理解为是window调用的),所以this指向window。
1 | function f(){ |
上面的例子,“o.f()”表示是由对象o调用的f,所以f中的this指向o。
三、构造函数中的this
1 | var that; |
上面的例子表明构造函数里的this指向构造函数产生的实例。
有在其它资料里看到一个理论:如果构造函数中有return 对象,那么this指向该对象,我觉得这个说法是错误的。(彻底理解js中this的指向,不必硬背。)在这篇文章里作者举例
1 | function fn() |
如果没有return返回的实例应该是有user属性的,于是得出结论说this是指向返回的对象的,这个是站不住脚的。我们可以看下面的代码
1 | function F(name){ |
从结果可以看出,this还是指向F产生的实例的,只是构造函数返回的不是其生成的实例,而是返回了return语句的返回值。
四、js事件回调函数里的this
1 | var btn = document.getElementsByTagName('body')[0]; |
上面的事件绑定,给btn对象新增了一个方法,当事件被触发的时候自然会执行btn.onclick,因此this指向btn是顺理成章的。下面的事件监听方法的回调函数里的this又是什么情况呢?1
2
3
4var btn = document.getElementsByTagName('body')[0];
btn.addEventListener('click',function(){
console.log(this === btn);//true
},false);
上面的代码,给btn元素绑定了一个click事件,当事件触发时打印出的结果表明this指向btn对象。其实我们可以将其归到第一种情况:“函数中的this总是指向调用它的对象”。上面的事件监听方法给btn添加了一个“click”方法,当监听到click事件时,btn对象会调用其“click”方法(直接执行btn.click()方法可以模拟点击事件),于是this自然指向调用它的btn对象。
五、apply、call、bind方法里的this
1 | function f(){ |
上面的例子通过apply改变了函数中this的指向
六、几个实际例子
1.jquery的ajax,this的指向问题
1 | var obj = { |
上面的例子是jquery里ajax方法的调用,第二行的this来自全局环境window,自然是指向window,但success为什么会指向obj呢?由于传入的obj中包含的success方法,会在请求成功时被调用,可以想象,调用的时候执行的应该是obj.success(res),因此,根据第1种情况所说success里的this指向的是调用它的obj对象,也就是这里传入$.ajxa()中的对象。
2.请说明要输出正确的myName的值要如何修改程序?并解释原因
1 | foo = function(){ |
这个例子里倒数第二行产生了一个实例,构造函数foo为该实例赋予myName属性。最后一行调用f.bar()时,直接调用对象是f,因此setTimeout里的this指向的是f。sayHello函数会在1000毫秒后由js引擎调用,因此执行的时候函数里的this会指向window,这里显然是想弹出f里的myName属性,我们只需要让sayHello执行的时候this指向f就好了。可以将bar那句改写成如下形式
1 | setTimeout(this.sayHello.bind(this), 1000); |