this到底指向谁,估计很多人在使用javascript的过程中都遇到过,这个关键字如果没搞懂,在一些高级功能中都会困难重重,搜了下相关文章,介绍的都挺多的,也有很深入的,比如汤姆大叔的《深入理解javascript系列》文章。看到很多文章中提到一句话:"this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象"。
《javascript设计模式与实践》中是这样说的:javascript的this总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。
除去不常用的with和eval,实际应用中,this的指向大致分为下面4种情况:
1、作为对象的方法调用。
2、作为普通函数调用。
3、构造器函数调用。
4、call和apply调用。
情况1:作为对象的方法调用
当函数作为对象的方法调用时,this指向该对象。这是最常见的,比如:
var obj={ a:1, fun:function(){ console.log(this.a);//输出:1 } }; obj.fun();
情况2:作为普通函数调用
当函数不作为对象的属性调用时,即作为普通函数调用,this总是指向全局对象。
var a=1; function fun(){ var a=2; console.log(this.a);//输出:1
console.log(a);//输出:2 } fun();
再看一种情况:
var name="张三"; var obj={ name:"李四", getName:function(){ console.log(this.name); } } obj.getName();//输出:李四 var getName=obj.getName; getName();//输出:张三
直接调用obj.getName(),这里的this是作为对象的方法调用,所以它指向obj,this.name就是李四;
obj.getName赋值给getName后,getName就变成了普通函数,所以指向的是全局的window.name,结果是张三;
举个在实际开发过程中遇到的会让人困惑的例子:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> </head> <body> <button id="btn">点我</button> <script type="text/javascript"> var id="window"; document.getElementById("btn").onclick=function(){ alert(this.id);//输出:btn var callback=function(){ alert(this.id);//输出:window } callback(); } </script> </body> </html>
点击按钮的时候this指向的是按钮,但是callback是作为普通函数调用的,里面的this指向的是全局对象window,所以结果是window。
此时我们可以临时用一个变量保存对当前对象的引用:
var id="window"; document.getElementById("btn").onclick=function(){ var self=this; var callback=function(){ alert(self.id);//输出:btn } callback(); }
情况3:构造器中调用
function myClass(){ this.name="张三"; } var child=new myClass(); console.log(child.name);//输出:张三
大部分的javascript函数都可以当做构造函数来使用,构造器函数外表跟普通函数一模一样,区别在于调用的方式。当使用new运算符调用函数时,该函数总会返回一个对象,就是我们常说的实例对象。通常情况下,通过new运算符后,构造器函数中的this就指向的实例对象。
注意:如果构造器函数显式的返回了一个object类型的休息,那么运算结果最终会返回这个对象,而不是上面所期望的。例如:
function myClass(){ this.name="张三"; return { name:"李四" } } var child=new myClass(); console.log(child.name);//输出:"李四" console.log(child);//输出:[object Object] {name: "李四"}
这个例子与上面的例子差别就在于构造器函数最后返回了一个对象。如果构造器函数不显式的返回任何数据,或者返回一个非对象类型的数据,就不会出现这种情况,例如:
function myClass(){ this.name="张三"; return "李四" } var child=new myClass(); console.log(child.name);//输出:张三 console.log(child);//输出:[object Object] {name: "张三"}
情况4:call和apply
call和apply能够动态的修改传入函数的this:
var obj1={ name:"张三", getName:function(){ console.log(this.name); } }; var obj2={ name:"李四" }; obj1.getName();//输出:"张三" obj1.getName.call(obj2);//输出:"李四" obj1.getName.apply(obj2);//输出:"李四"
call和apply的作用这里就不详细说了。