【面試小題】你不是很懂this嗎,做道題試試?

樑仔發表於2019-01-09

題目

請寫出程式碼執行的結果。

var length = 10;

function fn() {
  console.log(this.length);
}

var obj = {
  length: 5,
  method: function(fn) {
    fn();
    arguments[0]();
  }
};

obj.method(fn, 1);
複製程式碼

先不要看答案,思考思考。會輸出 5 嗎?

答案

瀏覽器環境下:

10
2
複製程式碼

node 環境:

undefined
2
複製程式碼

思考

這段程式碼十分有趣,是一個 this 作用域的問題。

這裡其實是耍了一個小聰明,已經不是單純的考 this,在 this 結合了 arguments 後,意圖把人迷惑。

arguments[0]()的列印結果是 2,能猜出 this 指向 arguments 所以輸出arguments.length

為什麼 this 指向了 arguments?

在 JS 裡 arguments 是一個類陣列物件(是物件,但是長的比較像陣列,又欠缺一些陣列的方法),其儲存的是函式的引數。arguments可以這樣理解:

arguments = {
  0: fn,
  1: 第二個引數, //沒有
  2: 第三個引數, //沒有
  ...,
  length: 1 //只有一個引數
}
複製程式碼

這裡 arguments[0]指代的就是method函式的第一個引數:fnarguments[0]()似乎可以看做是arguments.0(),(但應該不允許後者這樣寫),所以 arguments[0]()的意思就是:fn(),就合理解釋了 this 指向 arguments。

瀏覽器中的 this

js 中 this 指的是當前物件,如果在全域性範圍內使用 this,瀏覽器環境下則指代當前頁面 window

如果在函式中使用 this,則 this 指代什麼是根據當前函式是在什麼物件上呼叫。

所以,第一次執行 fn 比較沒有爭議,瀏覽器列印是 10。

除此之外,在內聯事件中,也要注意:

當程式碼被內聯處理函式呼叫時,它的 this 指向監聽器所在的 DOM 元素

<button onclick="console.log(this)">what is this</button>
複製程式碼

nodejs 中的 this

全域性中的 this

node 全域性中 this 與 global 物件沒有任何的關係,全域性中的 this 預設是一個空物件,指向的是 module.exports。這就涉及到 nodejs 的模組化了,nodejs 中存在模組作用域,感興趣的可以自行百度瞭解。

函式中的 this

在函式中 this 指向的是 global 物件,和全域性中的 this 不是同一個物件,在函式中通過 this 定義的變數就是相當於給 global 新增了一個屬性,此時與全域性中的 this 已經沒有關係了。

建構函式中的 this

在建構函式中 this 指向的是它的例項,而不是 global,這個比較好理解。

其他 JS 執行環境

有些 JS 執行環境下還會存在 this 是undefined的情況,報錯:

TypeError: Cannot read property 'length' of undefined
複製程式碼

相關文章