this的指向
除去不常用的with和eval的情况,大致可以分为以下4种情况:
1.作为对象的方法
2.作为普通函数调用
3.构造器调用
4.Function.prototype.call或Function.prototype.apply调用。
1.作为对象的方法调用
当函数作为对象的方法被调用时,this指向该对象。
1 2 3 4 5 6 7 8
| var obj = { a:1, getA: function(){ alert(this === obj); alert(this.a); } } obj.getA();
|
2.作为普通函数调用
当函数不作为对象的属性被调用时,也就是我们常说的普通函数方式,此时的this总是指向全局对象。
在浏览器的Javascript里,这个全局对象是window对象。
1 2 3 4 5
| window.name = "globalName"; var getName = function(){ return this.name; }; console.log(getName());
|
1 2 3 4 5 6 7 8 9 10 11
| window.name = "globalName"; var myObject = { name:'sven', getName: function(){ return this.name; } } var getName = myObject.getName; console.log(getName()); console.log(myObject.getName());
|
有时候我们会遇到一些困扰,比如在div节点的事件函数内部,有一个局部的callback方法,callback被作为普通函数调用时,callback内部的this指向了window,但我们往往是想让它指向该div节点,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <html> <body> <div id="div1">我是一个div</div> </body> <script> window.id = "window"; document.getElementById('div1').onclick = function(){ alert(this.id); //输出: div1 var callback = function(){ alert(this.id); //输出window } callback(); } </script> </html>
|
此时有一种简单的解决方案,可以用一个变量保存div节点的引用:
1 2 3 4 5 6 7 8
| window.id = "window"; document.getElementById('div1').onclick = function(){ alert(this.id); var callback = function(){ alert(this.id); } callback(); }
|
在ECMAScript5的strict模式下,这种情况下的this已经被规定为不会指向全局对象,而是undefine。
3.构造器调用
javascript没有类,但是可以从构造器中创建对象,同时提供了new运算符,使构造器看起来像一个类。
除了宿主提供的一些内置函数,大部分javascript函数都可以当做构造器使用。
构造器的外表跟普通函数一模一样,它们的区别在于被调用的方式。
当用new运算符调用函数时,该函数总会返回一个对象,通常情况下,构造器里的this就指向返回的这个对象。
1 2 3 4 5
| var MyClass = function(){ this.name = "sven"; } var obj = new MyClass(); console.log(obj.name);
|
注意:如果构造器显式地返回了一个object类型的对象,那么此次运算结果最终会返回这个对象。
1 2 3 4 5 6 7 8
| var MyClass = function(){ this.name = "sven"; return{ name: 'anne' } } var obj = new MyClass(); console.log(obj.name);
|
如果不显式地返回任何数据(即第一种情况),或者返回一个非对象类型的数据(如下),就不会造成这个问题。
1 2 3 4 5 6
| var MyClass = function(){ this.name = "sven"; return 'anne'; } var obj = new MyClass(); console.log(obj.name);
|
4.Function.prototype.call或Function.prototype.apply调用
跟普通的函数调用相比,这两个方法可以动态改变传入函数的this。
1 2 3 4 5 6 7 8 9 10 11
| var obj1 = { name: 'sven', getName: function(){ return this.name; } }; var obj2 = { name: 'anne' }; console.log(obj1.getName()); console.log(obj1.getName.call(obj2));
|
参考:
《javascript设计模式与开发实践》曾探著
JS 中 this 关键字详解