【讀書筆記】你不知道的JavaScript--this

this 其實是在函數被調用時發生的綁定,它指向什麼徹底取決於函數在哪裏被調用(也就是函數的調用方法)。數組

1. 默認綁定

獨立函數調用時,應用 this 的默認綁定, this 指向全局對象
若是使用嚴格模式(strict mode),那麼全局對象將沒法使用默認綁定,所以 this 會綁定到 undefined
觀察下面這段代碼瀏覽器

function aba () {
    console.log(this)
}
function bab () {
    "use strict"
    console.log(this)
}
var obj = {
    aba: aba,
    bab: bab
}
aba() //Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
bab()  //undefined
obj.aba() //{aba: ƒ, bab: ƒ}
obj.bab() //{aba: ƒ, bab: ƒ}

2. 隱式綁定

在一個對象內部包含一個指向函數的屬性,並經過這個屬性間接引用函數,從而把 this 間接(隱式)綁定到這個對象上。
當函數引用有上下文對象時,隱式綁定規則會把函數調用中的 this 綁定到這個上下文對象。
因此上個示例代碼中, 調用 obj.aba()this 被綁定到 obj,所以 this.abaobj.aba 是同樣的。app

對象屬性引用鏈中只有最頂層或者說最後一層會影響調用位置。函數

function foo() {
    console.log( this.a );
}
var obj2 = {
    a: 42,
    foo: foo
};
var obj1 = {
    a: 2,
    obj2: obj2
};
obj1.obj2.foo(); // 42

一個最多見的 this 綁定問題就是被隱式綁定的函數會丟失綁定對象,也就是說它會應用默認綁定,從而把 this 綁定到全局對象或者 undefined 上,取決因而否是嚴格模式。post

function fun1 () {
    console.log(this)
}
var obj = {
    fun1: fun1,
    fun2: function () {
        console.log(this)
    }
}
var getfun1 = obj.fun1
var getfun2 = obj.fun2
function doCallBack (cb) { //參數傳遞其實就是一種隱式賦值,所以咱們傳入函數時也會被隱式賦值
    cb()
}
function testSetTimeout (fun) {
    setTimeout(fun, 0)
}
fun1()                    // Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
obj.fun1()                // {fun1: ƒ, fun2: ƒ}
obj.fun2()                // {fun1: ƒ, fun2: ƒ}
getfun1()                 // Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
getfun2()                 // Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
doCallBack(obj.fun1)      // Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
doCallBack(obj.fun2)      // Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
testSetTimeout(obj.fun1)  // Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
testSetTimeout(obj.fun2)  // Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}

3. 顯式綁定

使用 callapplybind 或者箭頭函數顯示綁定函數調用的 this
若是把 null 或者 undefined 做爲 this 的綁定對象傳入 callapply 或者 bind,這些值在調用時會被忽略,實際應用的是默認綁定規則this

var obj = {
    c: 33,
    fun: function (a,b) {
        console.log( "a:" + a + ", b:" + b + ", c:" + this.c )
    }
}
// 把數組「展開」成參數
obj.fun.apply( null, [2, 3] ); a:2, b:3, c:undefined
// 使用 bind(..) 進行柯里化
var bar = obj.fun.bind( null, 2 );
bar( 3 ); // a:2, b:3, c:undefined

上面代碼中 applybind 這兩種方法都須要傳入一個參數看成 this 的綁定對象。若是函數並不關心 this 的話,仍然須要傳入一個佔位值,這時 null 多是一個不錯的選擇。
可是若是某個函數確實使用了 this,那默認綁定規則會把 this 綁定到全局對象(在瀏覽器中這個對象是 window),這將致使不可預計的後果(好比修改全局對象)。code

4. new綁定

在 JavaScript 中,構造函數只是一些被 new 操做符調用的普通函數而已。
實際上並不存在所謂的「構造函數」,只有對於函數的「構造調用」。對象

使用 new 來調用函數,或者說發生構造函數調用時,會自動執行下面的操做。
1 建立(或者說構造)一個全新的對象。
2 這個新對象會被執行 [[ 原型 ]] 鏈接。
3 這個新對象會綁定到函數調用的 this。
4 若是函數沒有返回其餘對象,那麼 new 表達式中的函數調用會自動返回這個新對象。ip

注意: 對 bind 返回的函數進行構造調用時,實際調用的是原函數,調用 bind 時傳入的第一個參數將被忽略,剩餘參數做爲構造調用的參數傳入原函數get

function test (a, b) {
    this.a = a
    this.b = b
    this.say = function () {
        console.log(`a: ${this.a}, b: ${this.b}, c: ${this.c}`)
    }
}
var bindObj = {
    c: 12
}
var bindReturn = test.bind(bindObj, 1, 2)
var newBindReturn = new bindReturn()
newBindReturn.say()  // a: 1, b: 2, c: undefined
console.log(bindObj) // {c: 12}
bindReturn()
console.log(bindObj) // {c: 12, a: 1, b: 2, say: ƒ}
相關文章
相關標籤/搜索