Javascript
Hoisting

Hoisting

Hoisting 是一個在 javascrpit 中會看到的機制/現象,首先要先了解 Execution Context 在執行上有兩個階段:Creation PhaseExecution Phase,在 Creation Phase 的時候,JS Engine 會做一個 Global Execution Context 出來,然後建立 this object 並綁到 global object,接下來會將 variables 跟 function 登記到記憶體位置上,這時給他們的值是 undefined,最後這個步驟就是 Hoisting 了,實際上沒有東西真的被「提升」,只是先分配到記憶體位置上。

所以到了 Execution Phase 的時候,variables 們如果在真的被指派值之前去使用它,會發現他們的值是 undefined,而 function 因為已經存到記憶體上了,即使 lexical 看上去還沒執行到那邊,還是可以順利執行。

console.log(a);
console.log(b());
 
// undefined
// "this is b!"
// undefined
 
var a = 3;
function b() {
  console.log("this is b!");
  return a;
}
 
console.log(a);
console.log(b());
 
// 3
// "this is b!"
// 3

Arrow Function

上述的例子如果把 b 改成 arrow function,因為 arrow function 並不會被 Hoist,所以呼叫的當下 b 是作為 variables 被 Hoist 設為 undefined,若在指派之後才 console.log 就沒有錯誤了。

console.log(b());
 
// Uncaught TypeError: b is not a function
 
var b = () => {
  console.log("this is b!");
  return a;
};

另一個常見的場景是,用 const/let 搭配 arrow function assign 時,在 execution phase 前期 const/let hoist 會在 TDZ 不能用(var 則如上所說還是 undefined),而用 function 宣告時會正常 hoist,常見把 function 放到最後面來讓程式碼好讀一點,除了寫 callback 以外的場合用 function 去宣告其實也不錯。

add(4, 5);
// Error: Block-scoped variable 'add' used before its declaration.
 
add2(4, 5);
// OK!
 
const add = (a: number, b: number) => {
  return a + b;
};
 
function add2(a: number, b: number) {
  return a + b;
}

this in arrow function

另外 Arrow function 中的 this 表示的是往外一層的物件。

const cat = {
  name: "Latte",
  weight: 6,
  printIntro: () => {
    console.log(`The weight of ${this.name} is ${this.weight} KG.`);
  },
};
 
cat.printIntro();
 
// -> The weight of undefined is undefined KG.
 
const cat = {
  name: "Latte",
  weight: 6,
  printIntro: function () {
    console.log(`The weight of ${this.name} is ${this.weight} KG.`);
  },
};
 
cat.printIntro();
 
// -> The weight of Latte is 6KG.