深入理解 javascript 中的 this 指向
别指望看几篇讲解就能看懂js里面的this。我也是前后翻阅了很多资料最后稍微有点懂的。
javascript里面的this跟大多数语言类似,总是指的一个对象,而具体的指向哪个对象是在运行时基于函数的执行环境动态绑定的,二不是函数被声明时的环境。
基本 this的指向大致分为以下四种
作为对象的方法调用
作为普通函数调用
构造器调用
Function.prototype.call或Function.prototype.apply调用
下面详细讲解下
1、作为对象的方法调用
当函数作为对象的方法调用的时候,this指向该对象
var obj = { a: 1, getA: function () { alert(this === obj);//true alert(this.a);//1 } }; obj.getA();
2、作为普通函数调用
当函数不作为对象的属性被调用的时候,也就是我们常说的普通函数方式,此时this总是指向全局对象,在浏览器的javascript里,这个全局对象就是window对象。
window.name ='globalName'; var getName = function(){ return this.name; }; console.log(getName()); //globalName //or window.name ='globalName'; var myobj ={ name:'sven', getName:function(){ return this.name; } }; myobj.getName() ;//sven var getName = myobj.getName; console.log(getName());// globalName
但是有时候我们会遇到一些困扰,比如在div节点的时间函数内部,有一个局部的callback方法,callback被作为普通函数调用时,callback内部的this指向了window,但是我们往往想让他指向该div节点,代码:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div id="div1">我是一个div</div> <script> window.id = "window"; document.getElementById("div1").onclick = function () { alert(this.id); var callback = function () { alert(this.id); }; callback(); } </script> </body> </html>
此时有一个简单的解决方案,可以用一个变量保存div节点的引用。
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div id="div1">我是一个div</div> <script> window.id = "window"; document.getElementById("div1").onclick = function () { var that =this; alert(this.id); var callback = function () { alert(that.id); }; callback(); } </script> </body> </html>
在ECMAScript 5的 严格模式下,这种情况的this已经被规定为不会指向全局对象,而是undefined。
3、构造器调用
javascript中没有类,但是可以从构造器中创建对象,同事也提供了new的运算符,使得构造器看起来更像一个类。
除了宿主提供一些内置函数,大部分的javascript函数都可以当做构造器使用。构造器的外表跟普通函数一模一样,他们的区别在于被调用的方式,当用new运算符调用函数时,该函数总是会返回一个对象,通常情况下,构造器里的this就指向返回的这个对象,如下代码:
var MyClass = function () { this.name = 'sven'; }; var obj = new MyClass(); alert(obj.name); //sven
但用new 调用构造器时,还要注意一个问题,如果构造器显式地返回一个object类型的对象,那么此次运算结果最终会返回这个对象,而不是我们期待的this:
var MyClass = function () { this.name = 'sven'; return { //显式滴返回了一个对象 name: 'anne' } }; var obj = new MyClass(); alert(obj.name); //anne
如果构造器不显式地返回任何数据,或者是返回一个非对象类型的数据,就不会造成以上的问题:
var MyClass = function () { this.name = 'sven'; return 'anne'; }; var obj = new MyClass(); alert(obj.name); //sven
4、Function.prototype.call或Function.prototype.apply调用
跟普通的函数调用想必,用Function.prototype.call或Function.prototype.apply可以动态第改变传入函数的this:
var obj1 = { name: 'sven', getName: function () { return this.name; } }; var onj2 = { name: 'anne' }; console.log(obj1.getName());//sven console.log(obj1.getName.call(obj2));//anne
call 和 apply的方法能很好滴体验javascript的函数式编程特性,在javascript中,几乎每一次编写函数式风格的代码,都离不开call和apply。