重讀你不知道的JS (上) 第一節四章

言月發表於2019-02-16

你不知道的JS(上卷)筆記

你不知道的 JavaScript

JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多複雜微妙技術的語言,即使是經驗豐富的 JavaScript 開發者,如果沒有認真學習的話也無法真正理解它們.

上捲包括倆節:

  • 作用域和閉包
  • this 和物件原型

作用域和閉包

希望 Kyle 對 JavaScript 工作原理每一個細節的批判性思 考會滲透到你的思考過程和日常工作中。知其然,也要知其所以然。

提升

作用域同其中的變數宣告出現的位置有某種微妙的聯絡

案例1

a = 2;
var a;
console.log( a ); // 在不瞭解宣告提升的情況下,你可能得出結果是undefined?  實際是2

案例2

console.log( a ); // 你可能由於案例1的影響,得出2,或者未宣告便使用,ReferenceError異常,實際上輸出 undefined
var a = 2;

看看編譯器怎麼說:

正確的思考思路是,包括變數和函式在內的所有宣告都會在任何程式碼被執行前首先 被處理。

編譯 -> 解釋js程式碼 -> 執行

只有宣告本身會被提升,而賦值或其他執行邏輯會留在原地。如果提升改變了程式碼執行的順序,會造成非常嚴重的破壞。

函式宣告會被提升,但是函式表示式卻不會被提升。

foo(); // 不是 ReferenceError, 而是 TypeError!
var foo = function bar() { // ...
};

foo()呼叫執行時,foo 此時並沒有賦值(如果它是一個函式宣告而不 是函式表示式,那麼就會賦值)。foo() 由於對 undefined 值進行函式呼叫而導致非法操作, 因此丟擲 TypeError 異常。

函式優先

函式宣告和變數宣告都會被提升,但是函式會首先被提升,然後才是變數。

一個普通塊內部的函式宣告通常會被提升到所在作用域的頂部,這個過程不會像下面的代 碼暗示的那樣可以被條件判斷所控制:

foo(); // "b"
var a = true; 
if (a) {
  function foo() { console.log("a"); }
}
else {
  function foo() { console.log("b"); }
}

小結

我們習慣將var a = 2;看作一個宣告,而實際上JavaScript引擎並不這麼認為。它將var a
和 a = 2 當作兩個單獨的宣告,第一個是編譯階段的任務,而第二個則是執行階段的任務。
這意味著無論作用域中的宣告出現在什麼地方,都將在程式碼本身被執行前首先進行處理。 可以將這個過程形象地想象成所有的宣告(變數和函式)都會被“移動”到各自作用域的 最頂端,這個過程被稱為提升。

宣告本身會被提升,而包括函式表示式的賦值在內的賦值操作並不會提升。 要注意避免重複宣告,特別是當普通的 var 宣告和函式宣告混合在一起的時候,否則會引起很多危險的問題!

相關文章