this
關鍵詞this關鍵詞是JavaScript語言中一個很重要,同時也是一個很是複雜的機制,它同時也是一個很特殊的關鍵詞,它通常會被自動定義在函數的做用域中。很多頗有經驗的開發者也常常會被this
的指向搞暈,當開發者搞不清楚它的指向的時候,心裏的感覺實際上差很少是這個樣子:![]()
接下來咱們將會具體討論this
關鍵詞到底指向什麼。
this
的綁定規則首先明確一點,this
的綁定和函數的聲明位置是沒有任何關係的,它只取決於函數的調用位置和調用方式。jquery
首先咱們先看一下最多見的也是最簡單的函數調用,全局中的獨立的函數調用:編程
var a = 'hello'; function foo() { console.log(this.a); } foo();// "hello"
衆所周知,聲明在全局做用域中的變量,就是全局對象(window
或者global
)的一個同名的屬性,在本例中,this.a
被解析成了全局變量a
,而函數foo
就是在直接在全局對象下、不帶有任何修飾地進行調用的,因此,this
的默認綁定規則就是指向全局對象
。可是,當咱們使用嚴格模式(strict)進行開發的時候,狀況發生了變化app
"use strict"; var a = 'hello'; function foo() { console.log(this.a); } foo();// undefined
在嚴格模式下,this
被禁止綁定到全局對象中,因此在本例中,this
指向了undefined
。函數
看下面的代碼:this
var a ="world"; var foo = function () { console.log(this.a); }; var obj = { a:"hello", b:foo }; obj.b(); //"hello"
本例中,分別在全局對象中定義變量a
,和在全局對象中定義屬性obj.a
,運行結果是this
被綁定到了被調用函數所在的對象中,而並不是是全局對象中的a
,或者你能夠說,this
指向了該函數的上級對象中。可是嚴格來講,不管是直接在obj
對象中直接定義,仍是先在全局對象中定義再添加到obj
中,foo
函數都並不屬於obj
對象,然而調用位置會使用obj的上下文來引用函數。簡單說,當函數引用有上下文對象時,隱式綁定
規則會將函數調用中的this
綁定到這個上下文對象中。spa
var Foo = function () { this.a = 'hello'; } Foo.prototype.bar = function () { console.log(this.a); }; Foo.prototype.bar2 = function () { this.bar(); }; var foo = new Foo(); foo.bar2();//"hello"
本例與上例相似,this在「Foo類」(嚴格說Foo是應該是構造函數,但通常在開發過程當中認爲Foo是類,這樣有助於在面向對象編程中減小誤解)中綁定的是「類」裏的共有變量和共有方法。prototype
this
隱式綁定丟失上述的幾種應用場景仍是很是容易理解的,也是比較符合咱們對this
字面意義的理解的,相信對JavaScript有過接觸和研究的童鞋很快就會掌握。下面將繼續介紹幾種讓人感受匪夷所思的this
綁定丟失。
思考如下代碼:code
var a = "world"; function foo (){ console.log(this.a); } var obj = { a:"hello", foo:foo }; var bar = obj.foo; //函數別名 bar(); //"world"
代碼執行完成後,咱們看到this
被綁定到了(或者說指向了)全局對象上,而並非和前幾種狀況下綁定到obj
對象中,這是爲啥呢?
雖然bar
是obj.foo
的一個引用,可是實際上它引用的是foo
函數自己,所以此時bar
實際上是一個不帶任何修飾的函數調用,所以適用於默認綁定狀況。
下面再來看看回調函數中this
的綁定狀況對象
function foo() { console.log(this.a); } function do(fnc) { fnc(); }; var obj = { a:2, foo:foo }; var a = "world"; do(obj.foo);//"world"
參數傳遞其實就是一種隱式賦值,所以傳入函數時也會被隱式賦值,因此結果和上一個例子沒有區別,即使是將函數傳入語言內置的的函數(好比setTimeout()
)中,結果也是沒有區別的,this
要麼被綁定到全局對象中,要麼綁定到undefined
。
除此以外,還有一種狀況也會修改this
,在一些JavaScript庫中傳入回調函數,可能會強制改變this
的綁定,例如在jquery中事件
$("#some-id").on('click',function () { console.log(this.id);//"some-id" });
本例中的this
就是被強制改變綁定到了觸發事件的DOM元素上。
隱式綁定實際上就是在一個對象的內部包含一個指向函數的屬性,並經過這個屬性間接地引用屬性,從而把this
間接地綁定到這個對象上。
咱們可使用call
和apply
兩個函數進行顯式綁定。它們的第一個參數是一個對象,它們會把這個對象綁定到this
,接着在調用函數時指定這個this
。
var a = "world"; function foo() { console.log(this.a); } var obj = { a:"hello" }; foo.call(obj);//"hello" foo() //"world"
單純的實現this
綁定的功能的話,call
和apply
是同樣的,它們的區別體如今別的參數中。
思考下面的代碼:
function foo() { console.log(this.a); } var obj = { a:"hello" }; function bar() { foo.call(obj); } bar(); //"hello" setTimeout(bar,500);// "hello" bar.call(window); //"hello",硬綁定的bar不能再修改它的this
咱們建立了函數bar
,而且手動在它的內部調用foo.call(obj)
,所以強制把foo
的this
綁定到obj
,以後不管怎麼調用函數bar
,它總會在obj
上調用foo
,不會丟失,這種綁定方式被稱爲硬綁定
.