最近正在看《你不知道的JavaScript》,裏面關於this綁定機制的部分講的特別好,很清晰,這部分對咱們js的使用也是至關關鍵的,而且這也是一個面試的高頻考點,因此整理一篇文章分享一下這部分的內容,相信看本文的解析,你必定會有所收穫的,若是喜歡的話能夠點波贊/關注,支持一下。面試
我的博客瞭解一下: obkoro1.com
function identify() { console.log("Hello,I'm " + this.name); } let me = { name: "Kyle" }; let you = { name: "Reader" }; identify.call(me); // Hello,I'm Kyle identify.call(you); // Hello,I'm Reader
這個簡單的栗子,能夠在不一樣的對象中複用函數identify
,不用針對每一個對象編寫一個新函數。app
this解決的問題:ide
this提供了一種更優雅的方法來隱式'傳遞'一個對象的引用,所以能夠將API設計得更加簡潔而且易於複用。函數
規則:在非嚴格模式下,默認綁定的this
指向全局對象,嚴格模式下this
指向undefined學習
function foo() { console.log(this.a); // this指向全局對象 } var a = 2; foo(); // 2 function foo2() { "use strict"; // 嚴格模式this綁定到undefined console.log(this.a); } foo2(); // TypeError:a undefined
默認綁定規則如上述栗子,書中還提到了一個微妙的細節:this
function foo() { console.log(this.a); // foo函數不是嚴格模式 默認綁定全局對象 } var a = 2; function foo2(){ "use strict"; foo(); // 嚴格模式下調用其餘函數,不影響默認綁定 } foo2(); // 2
因此:對於默認綁定來講,決定this綁定對象的是函數體是否處於嚴格模式,嚴格指向undefined,非嚴格指向全局對象。spa
一般不會在代碼中混用嚴格模式和非嚴格模式,因此這種狀況很罕見,知道一下就能夠了,避免某些變態的面試題挖坑。設計
規則:函數在調用位置,是否有上下文對象,若是有,那麼this就會隱式綁定到這個對象上。3d
function foo() { console.log(this.a); } var a = "Oops, global"; let obj2 = { a: 2, foo: foo }; let obj1 = { a: 22, obj2: obj2 }; obj2.foo(); // 2 this指向調用函數的對象 obj1.obj2.foo(); // 2 this指向最後一層調用函數的對象 // 隱式綁定丟失 let bar = obj2.foo; // bar只是一個函數別名 是obj2.foo的一個引用 bar(); // "Oops, global" - 指向全局
隱式綁定丟失:code
隱式綁定丟失的問題:實際上就是函數調用時,並無上下文對象,只是對函數的引用,因此會致使隱式綁定丟失。
一樣的問題,還發生在傳入回調函數中,這種狀況更加常見,而且隱蔽,相似:
test(obj2.foo); // 傳入函數的引用,調用時也是沒有上下文對象。
就像咱們上面看到的,若是單純使用隱式綁定確定沒有辦法獲得指望的綁定,幸虧咱們還能夠在某個對象上強制調用對象,從而將this
綁定在這個函數上。
規則:咱們能夠經過apply
、call
、bind
將函數中的this
綁定到指定對象上。
function foo() { console.log(this.a); } let obj = { a: 2 }; foo.call(obj); // 2
傳入的不是對象:
若是你傳入了一個原始值(字符串,布爾類型,數字類型),來當作this的綁定對象,這個原始值轉換成它的對象形式。
若是你把null
或者undefined
做爲this的綁定對象傳入call
/apply
/bind
,這些值會在調用時被忽略,實際應用的是默認綁定規則。
書中提到:在js中,實際上並不存在所謂的'構造函數',只有對於函數的'構造調用'。
new的時候會作哪些事情:
規則:使用構造調用的時候,this會自動綁定在new期間建立的對象上。
function foo(a) { this.a = a; // this綁定到bar上 } let bar = new foo(2); console.log(bar.a); // 2
若是在某個調用位置應用了多條規則,如何肯定哪條規則生效?
obj.foo.call(obj2); // this指向obj2 顯式綁定比隱式綁定優先級高。 new obj.foo(); // thsi指向new新建立的對象 new綁定比隱式綁定優先級高。
顯式綁定和new綁定沒法直接比較((會報錯),默認綁定是不該用其餘規則以後的兜底綁定因此優先級最低,最後的結果是:
顯式綁定 > 隱式綁定 > 默認綁定
new綁定 > 隱式綁定 > 默認綁定
function foo() { return () => { console.log(this.a); }; } let obj1 = { a: 2 }; let obj2 = { a: 22 }; let bar = foo.call(obj1); // foo this指向obj1 bar.call(obj2); // 輸出2 這裏執行箭頭函數 並試圖綁定this指向到obj2
從上述栗子能夠得出,箭頭函數的this規則:
this
繼承於它外面第一個不是箭頭函數的函數的this
指向。認真看完的話,相信你已經get到this的用法了,最後推薦一下《你不知道的JavaScript》,這本書真的很好,寫的也頗有趣,沒看過的小夥伴抓緊入手了。
PS:目前離職中,大佬們有坑位能夠介紹一下呀,base:上海長寧。
我的blog and 掘金我的主頁,如需轉載,請放上原文連接並署名。碼字不易,感謝支持!
若是喜歡本文的話,歡迎關注個人訂閱號,漫漫技術路,期待將來共同窗習成長。
以上2018.6.30