箭頭函式this指向的陷阱

Colin_Mindset發表於2019-04-27

箭頭函式沒有this
箭頭函式沒有this!!
箭頭函式沒有this!!!

重要的事情說三遍!


那你可能要問我在箭頭函式中明明可以取到this啊!

function foo() {
  this.a = 1
  let b = () => console.log(this.a)

  b()
}

foo()  // 1

以上箭頭函式中的this其實是父級作用域中的this,箭頭函式引用了父級作用域的變數,構成了一個閉包。

以上程式碼等價於:

function foo() {
  this.a = 1

  let self = this
  let b = () => console.log(self.a)

  b()
}

foo()  // 1

箭頭函式不僅沒有this,常用的arguments也沒有。如果你能獲取到arguments,那它一定是來自於父級作用域

function foo() {
  return () => console.log(arguments[0])
}

foo(1, 2)(3, 4)  // 1

如果箭頭函式有arguments,就應該輸出3而不是1。
一個常犯的錯誤是使用箭頭函式定義物件的方法,如:

let a = {
  foo: 1,
  bar: () => console.log(this.foo)
}

a.bar()  //undefined

以上程式碼中,箭頭函式中的this指向並不是指向a這個物件。物件a並不能構成一個作用域,所以再往上到達全域性作用域this就指向全域性作用域。如果我們使用普通函式的定義方法,輸出結果就能符合預期,這是因為a.bar()函式執行時作用域繫結到了a物件。

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

a.bar()  // 1

以上文章提到了this指向和作用域概念,這裡進一步介紹下。

this指向

首先必須要說的是,this的指向在函式定義時是確定不了的,只有函式執行時才能確定,實際上this最終指向的是呼叫它的物件。

在函式沒有呼叫時,this的值無法確定。

還是拿例子來說明,

function a(){
    var user = "追夢子";
    console.log(this.user); //undefined
    console.log(this); //Window
}
a();

因為this最終指向的是呼叫它的物件,函式a實際上是被window呼叫的。
再來個例子。

var o = {
    user:"追夢子",
    fn:function(){
        console.log(this.user);  //追夢子
    }
}
o.fn();

這裡this指向o,好像沒什麼好說的,最終指向呼叫它的物件。
好了,看到這裡還不要驕傲,下面幾個例子才有真正的坑。

var o = {
    a:10,
    b:{
        // a:12,
        fn:function(){
            console.log(this.a); //undefined
        }
    }
}
o.b.fn();

這是因為this指向的是上一級呼叫的物件,而不能一級一級往上尋找。

作用域

剛才講到普通函式的this指向是執行時確定的,然而,不同的是,

JavaScript中的作用域是的巢狀關係是定義時確定的。

也就是說,JavaScript的作用域是靜態作用域,又叫詞法作用域,這是因為作用域的巢狀關係在語法分析時就可以確定,而不是在執行時確定。
例如,

var scope = 'top';
  var f1 = function() { 
      console.log(scope);
  };
  f1(); // 輸出 top
  var f2 = function() { 
      var scope = 'f2'; 
      f1();
  };
   f2(); // 輸出 top`

參考

https://jingsam.github.io/2016/12/08/things-you-should-know-about-arrow-functions.html
https://segmentfault.com/a/1190000004589779
https://juejin.im/entry/589be5b1b123db16a3bec5c2
https://juejin.im/post/5aa1eb056fb9a028b77a66fd
https://segmentfault.com/a/1190000018119191

相關文章