JS Day 37: Var, Let and Const, part 2 - Hoisting

有 N 人看过

Hoisting 提升

Var Hoisting 變數提升

console.log(a); // undefined
var a = 'A';

// ---- 分隔線 ----

// 實際上這段程式碼對編譯器來說是長這樣
var a; // 只有宣告 a 這個變數
console.log(a); // 只有被宣告,但沒有賦予值,自然是 undefined
a = 'A'; // assignment 不會被提升

把上面的例子拆分,這樣子比較好理解。

var a; // 有宣告,但沒有賦予任何值
console.log(a);  // a 會是 undefined

使用 var 跟 let 的結果:

console.log(a); // Undefined
var a = 'A';

console.log(b);  // ReferenceError: b is not defined
let b = 'B'; 

console.log(c);  // ReferenceError: c is not defined
const c = 'C'; 

https://drive.google.com/uc?export=view&id=1ut6WFtMB7-4MUNbgfCZyn24ZzzjFdBxG

undefined =/= not defined
undefined 在記憶體已經有準備空間給它
not defined 沒有被定義

var 的特性,只要繼替體有準備位置,使用 var 會出現 hoisting (undefined),反之使用 let& const 則不會出現 hoisting(not defined),因為變數 b 之前不存在,所以會出錯。

提升 & 函式 (Hoisting & Functions)

函式運算式 (Function Declaration)

延續上方,console.log(a) 會是 undefined

alpha(); // 'Alpha calling...', function 會被提升
console.log(a); // undefined, var a 會被提升,但 assignment 不會
var a = 'A';

function alpha() {
    console.log('Alpha calling...');
};

// output
// Alpha calling...
// undefined
console.log(a); // function a()
var a;
function a() {
    console.log('say a word');
};

為何不是 undefined? 因為 function 被提升了。

類似範例:

aTest(); // 我被提升了
function aTest() {
    console.log('我被提升了');
};

範例1:

var a = 0;

function a() {
    return 1;
};

console.log(typeof a); // number

可以這樣解讀範例1:

var a; // 提升

function a() {
    return 1;
};

// 初始化, 不會被提升
a = 0

console.log(typeof a); // number

https://drive.google.com/uc?export=view&id=12oaRQd-9WaquBjqIhyNXLlAniBSu1ohq

這樣子寫 console 輸出也是 number。

範例2:

// var
var a;
function a() {
  return 1;
};

console.log(typeof a); // function

// let
let a;
function a() {
  return 1;
};

console.log(typeof a); // 重複宣告 let a
                                             // SyntaxError: redeclaration of let a

函式陳述式 (Function Expression)

console.log(typeof aTest); // undefined
aTest(); // function 沒有被提升,出錯了。
         // TypeError: aTest is not a function
var aTest = function hoist() {
    console.log('我被提升了');
};

var aTest 有被提升,但是 function 沒有,aTest 沒有被 initialize,所以是 undefined。

//
// var
aTest(); // function 沒有被提升,出錯了。
         // TypeError: aTest is not a function
var aTest = function() {
    console.log('我被提升了');
};

//
// let
aTest(); // function 沒有被提升,出錯了。
         // ReferenceError: can't access lexical declaration 'aTest' before initialization
let aTest = function() {
    console.log('我被提升了');
};

//
// const
aTest(); // function 沒有被提升,出錯了。
         // ReferenceError: can't access lexical declaration 'aTest' before initialization
const aTest = function() {
    console.log('我被提升了');
};

一樣都是 function,怎麼一個有被提升一個沒有呢?

letconst 宣告 function expression 都會出現很明確的錯誤:ReferenceError: can’t access lexical declaration ‘findProd’ before initialization (暫時性死區 Temporal Dead Zone, TDZ)。

  • 函式提升 > 變數提升
  • assignment (=) 不會被提升
  • Function Expression 不會被提升,function declaration 則會

Reference:
ECMAScript 6 入門: let 和 const 命令
重新認識 JavaScript: Day 10 函式 Functions 的基本概念
我知道你懂 hoisting,可是你了解到多深?
Hoisting in JavaScript

本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。