先知
this 實際上是在函式被呼叫時發生的繫結,它指向哪裡完全取決於函式在哪裡被呼叫。
大提示: 不想看分析的可以直接拉到最後看結論。
面試常見題
第一題
function foo(){
console.log(this.a)
}
var obj = {
a :2,
foo:foo
}
var bar = obj.foo
obj.foo()
bar()
複製程式碼
問: 最後兩個列印出什麼?
第二題
function foo(){
console.log(this.a)
}
var obj = {
a :2,
foo:foo
}
var obj2 = {
a:1,
obj:obj
}
var obj3 = obj2.obj.foo
obj2.obj.foo() // 2
obj3() //undefined
複製程式碼
問: 最後兩個列印出什麼? 答?
我們如何理解 this 繫結的到底是誰?或者說 this 到底是誰?下面介紹四種方法
1. 預設繫結
什麼是預設繫結呢?上程式碼先
var a = 2;
function foo(){
console.log(this.a)
}
function foo2(){
'use strict'
console.log(this.a)
}
foo() // 2
foo2() // TypeError: Cannot read property 'a' of undefined
複製程式碼
- 在上面的程式碼中,「 foo() 直接使用時不帶任何修飾的函式引用進行呼叫的 」, 因此只能使用「預設繫結」
- 所以到 foo() 中的 this 繫結到「 全域性物件 window 」,而「 嚴格模式 」時,全域性物件無法被繫結,所以 this 繫結到 「undefined」
預設繫結總結:預設繫結即不帶任何修飾的函式引用被呼叫時的繫結,此時 this 繫結到「 全域性物件 window 」或者 「undefined」
2. 隱式繫結
隱式繫結是什麼呢?隱式的繫結
當函式引用有上下文物件時,隱式繫結會把函式呼叫中的 this 繫結到這個上下文物件。
那麼回到面試題
2.1 面試題一
function foo(){ console.log(this.a)}
var obj = { a :2, foo:foo }
var bar = obj.foo
obj.foo() //2
bar() /undefined
複製程式碼
foo() 被呼叫時,落腳點指向 obj 物件(上下文物件),所以 this 繫結到 obj ,this.a 即 obj.a , 所以列印出了 2
但是為什麼 bar() 列印出了 undefined 呢?
雖然 bar 是 obj.foo 的引用,但實際上是 foo函式 本身的引用,所以此時 bar() 是不帶任何修飾的函式呼叫,使用預設呼叫
2.2 面試題二
function foo(){ console.log(this.a) }
var obj = { a :2, foo:foo }
var obj2 = { a:1, obj:obj }
var obj3 = obj2.obj.foo
obj2.obj.foo() // 2
obj3() //undefined
複製程式碼
跟上面一題相同,雖然引用鏈比較長,但是最後 foo() 是在 obj 中被呼叫,所以 this 繫結到 obj ,引用鏈只有最後一層影響呼叫位置。
隱式繫結總結 : 函式在上下文物件中呼叫時, this 繫結到 上下文物件上。
3. 顯式繫結
使用「 call apply bind 」 進行繫結 this , this 繫結到第一個傳入的引數
3.1 call 的使用
回到面試題第一題,我們使用「 call 」進行顯式繫結
function foo(){ console.log(this.a) }
var obj = {
a :2,
foo:foo
}
var bar =obj.foo
obj.foo() // 2
bar.call(obj) //2
複製程式碼
此時兩者都列印出 2 ,因為我們將 this 繫結到 obj ,列印出的即是 //obj.a //2
3.2 apply 繫結第一個引數是 this , 二參是 一個陣列
3.3 bind 是 繫結第一個引數是 this
顯式繫結總結: 使用call apply bind 時,第一個引數是 this ,不傳的話,預設為 undefined 。
4. new 繫結
使用 new 來呼叫函式, 到底做了什麼 ?
-
- 建立一個全新的物件
-
- 這個新物件的__proto__ 連結到 建構函式的 prototype
-
- 這個新物件會繫結到函式呼叫的 this
-
- 如果函式沒有返回其他物件,那麼 new 表示式中的函式呼叫會自動返回這個新物件。
function foo(a){
this.a = a
}
var bar = new foo(2)
console.log(bar.a) // 2
複製程式碼
分析: 使用 new 呼叫 foo() 時,我們構造一個物件並把它繫結到 foo() 呼叫的 this 上
####new 繫結總結: new 繫結中 this 繫結的就是新生成的物件
總結
-
- 「 箭頭函式 」內的 this 就是外面的 this ,外面的 this 是啥看下面四條
-
2 . 「 new 繫結 」函式是否在 new 中呼叫 ? 如果是 this 繫結的即是 新建立的物件。 var bar = new foo()
-
- 「 顯式繫結 」函式是否通過 call 、apply、 bind 繫結?this繫結的時第一個引數 var bar = foo.call(obj)
-
4.「 隱式繫結 」 函式是否在某個上下文中呼叫? 是的話,this 繫結的是那個上下文物件 var bar = obj.foo()
-
- 「 預設繫結」如果都不是,那麼就是預設繫結。嚴格模式繫結到 undefined ,否則繫結到 全域性物件 var bar = foo()
後記
你要是看不懂我也沒辦法了,我的修為都在這了。。。。
文章為個人總結,不足之處還請留言或私信。
轉載請註明出處。
以上。