1. 程式人生 > >JavaScript函式中this的四種繫結策略

JavaScript函式中this的四種繫結策略

this的四種繫結策略

  • 預設繫結
  • 隱式繫結
  • 顯示繫結
  • new繫結

1. 預設繫結

當一個函式沒有明確的呼叫物件的時候,也就是單純作為獨立函式呼叫的時候,將對函式的this使用預設繫結:繫結到全域性的window物件

// 第一個例子
var foo = function() {
    console.log(this.a);
}
var a = 2
foo() // 2
// 第二個迷惑性的例子
var foo = function() {
    var a = 3
    var inner = function() {
        console.
log(this.a); } inner() } var a = 2 foo() // 2

第二個例子雖然在foo()作用域內聲明瞭a變數為3, 但它並不是一個物件, 所以this最終還是會指向全域性的window物件

2. 隱式繫結

函式被呼叫時有上下文物件,那麼this會繫結這個上下文物件

書上寫的上下文物件意思很模糊, 覺得這裡翻譯的其實不太好

我感覺比較好的解釋是:當函式被一個物件包含的時候, 我們稱這個函式的this被隱式繫結到這個物件上了

var o = {
    a: 2,
    foo: function() {
        console.
log(this.a); }, }

在一串物件屬性引用鏈中, this繫結的是最內層的物件

var obj = {
      a: 1,
      obj2: {
           a: 2,
           obj3: {
                a:3,
                getA: function () {
                    console.log(this.a)   
                 }
           }
       }
}
obj.obj2.obj3.getA();  // 輸出3

隱式丟失

最常見的this繫結問題就是被隱式繫結的函式會丟失繫結物件, 也就是它會應用預設繫結, 把this繫結到全域性物件或者undefined上

var foo = function() {
    console.log(this.a);
}
var obj = {
    a: 2,
    foo: foo,
}
var a = 5
var bar = obj.foo 
bar() // 5

像這個例子, obj物件把foo函式的引用傳給bar的時候, 會丟失this對obj的繫結

回撥函式同樣也會丟失繫結

var foo = function() {
    console.log(this.a);
}
var obj = {
    a: 2,
    foo: foo,
}
var a = 5
setTimeout(obj.foo, 100) // 5

這種函式賦值的方式是無法將函式所繫結的this物件也傳遞過去的

3. 顯式繫結

顯式繫結是通過apply或者call函式繫結的物件

如果你想傳遞函式並且把所繫結的this物件也傳遞過去, 那麼就可以使用call()

fn.call(object)

  • fn是你呼叫的函式
  • object是你希望繫結的物件
  • 作用:即刻呼叫函式fn(), 呼叫時這個函式的this指向object
var foo = function() {
    console.log(this.a)
}
var obj = {
    a: 1,
}

foo.call(obj)

這樣做有個缺點, 每次呼叫都會依賴call

所以可以將它包裝成函式

var foo = function() {
    console.log(this.a)
}
var obj = {
    a: 1,
}
var bar = function() {
    foo.call(obj)
}
bar()

如果使用bind會更簡單

var foo = function() {
    console.log(this.a)
}
var obj = {
    a: 1,
}
var bar = foo.bind(obj)
bar()

call和bind的區別是:在繫結this到物件引數的同時:

  1. call將立即執行該函式
  2. bind不執行函式,只返回一個可供執行的函式

4. new繫結

來new來呼叫函式,會自動執行下列操作

  1. 建立一個全新的物件
  2. 這個新物件被執行[[prototype]]連線
  3. 這個新物件會繫結到函式呼叫的this
  4. 如果函式沒有返回其他物件,那麼new表示式中的函式呼叫會自動返回這個新物件
function foo(a) {
    this.a = a;
}

var bar = new foo(2)
console.log(bar.a) // 2

5. 優先順序

new繫結 > 顯示繫結 > 隱式繫結 > 預設繫結

參考資料:
你不知道的JavaScript(上卷)
【javascript】函式中的this的四種繫結形式