在 JavaScript 中,this
是动态绑定,或称为运行期绑定的。一般而言,在Javascript中,this
指向函数执行时的当前对象。
由于其运行期绑定的特性,JavaScript 中的 this
可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式。JavaScript 中函数的调用有以下几种方式:没有明确的调用对象,作为对象方法调用,使用 new
关键字作为构造函数调用,和使用 apply
、 call
和 eval
调用。
没有明确的当前对象时
当没有明确的执行时的当前对象时,this
指向全局对象 window
。
纯粹的函数调用
举个栗子
123456 |
var x = 1;function test(){ var x = 2; alert(this.x);}test(); // 1 |
再看个复杂的栗子
123456789101112131415161718 |
var name = "window"; var Bob = { name: "Bob", showName: function(){ alert(this.name); }}; var Tom = { name: "Tom", showName: function(){ var fun = Bob.showName; fun(); }}; Tom.showName(); //window |
其实也不复杂,只要按照上面那句话来判断就行。
setTimeout、setInterval和匿名函数
在浏览器中 setTimeout
、setInterval
和匿名函数执行时的当前对象是全局对象 window
,这条可以看成是上一条的一个特殊情况。
123456789101112 |
var name = "Bob"; var nameObj = { name : "Tom", showName : function(){ alert(this.name); }, waitShowName : function(){ setTimeout(this.showName, 1000); } }; nameObj.waitShowName(); // Bob |
setTimeout
可以看做是一个延迟执行的匿名函数。
12345 |
waitShowName : function(){ function(__callback){ __callback(); }(this.showName); } |
由于匿名函数的当前对象是 window
,所以当在该匿名函数中运行回调函数时,回调函数的 this
指向了 window
,所以 alert 出来 window.name
。
作为对象方法调用时
使用这种调用方式时,this
被自然绑定到该对象。
通常情况
12345678 |
var text = ‘window‘var obj = { text: ‘obj‘, foo: function(){ console.log(this.text); }}obj.foo(); // obj |
内部函数调用
但是,如果在 obj
的 foo()
内部再声明一个函数,在内部函数中调用 this
,像下面这样:
123456789101112 |
‘use strict‘;var obj = { text: ‘hello world‘, foo: function(){ return function(){ console.log(this.text); }() }} obj.foo(); // Uncaught TypeError: Cannot read property ‘text‘ of undefined |
这是因为 this
指针只在 foo 方法的函数内指向 obj ,在函数内部定义的函数, this
又指向undefined
了!(在非 strict
模式下,它重新指向全局对象 window
!)
修复的办法是用一个 that
变量首先捕获 this
:
1234567891011 |
‘use strict‘;var obj = { text: ‘obj‘, foo: function(){ var that = this; return function(){ console.log(that.text); }() }}obj.foo(); // obj |
三种特殊情况
new关键字 - 作为构造函数调用时
所谓构造函数,就是通过这个函数生成一个新对象。这时,this
就指这个新对象。
12345678910 |
function Person(__name){ this.name = __name; // this 指向使用该构造函数构造的新对象}Person.prototype.show = function(){ alert(this.name);} var Bob = new Person("Bob");Bob.show(); //Bob |
apply 和 call
在 JavaScript 中函数也是对象,对象则有方法,apply()
和 call()
就是函数对象的方法。它们能够强制改变函数执行时的当前对象,让 this
指向其他对象。
apply()
接收两个参数,第一个参数就是需要绑定的this变量,第二个参数是 Array,表示函数本身的参数。call()
与 apply()
的唯一区别就是把函数本身的参数一个个传入。
123 |
// 对普通函数调用,通常把 this 绑定为 nullMath.max.apply(null, [3, 5, 4]); // 5Math.max.call(null, 3, 5, 4); // 5 |
举个使用 apply()
改变当前对象的栗子:
123456789101112131415 |
var name = "window"; var someone = { name: "Bob", showName: function(){ alert(this.name); }}; var other = { name: "Tom"}; someone.showName.apply(); // windowsomeone.showName.apply(other); // Tom |
apply()
的参数为空时,默认调用全局对象。
eval
对于 eval
函数,其执行时候似乎没有指定当前对象,但实际上其 this
并非指向 window
,因为该函数执行时的作用域是当前作用域,即等同于在该行将里面的代码填进去。
12345678910 |
var name = "window"; var Bob = { name: "Bob", showName: function(){ eval("alert(this.name)"); }}; Bob.showName(); //Bob |