iT邦幫忙

2021 iThome 鐵人賽

DAY 19
0
自我挑戰組

Be friend with JavaScript系列 第 19

Day 19 - Execution Context

JavaScript 在運作時會建立執行環境,分為 Global Execution Context(全域) 和 Function Execution Context(函式)兩種。
而在執行環境建立的時候又分兩個階段,分別是 Creation Phase 和 Execution Phase,在 Creation Phase 時會建立 this 以及變數和函式的記憶體位置。
例如:
在 function 被執行前會先到 creation phase ,程式碼正式被運行後,才會到 execution phase 這個階段,並遵循 callstack 原則一行一行執行。

  • Global Execution Context
  • Function Execution Context

Hoisting

Hoisting 發生在 Creation phase
在執行程式碼之前(creation phase)電腦的記憶體只會分配給 function declaration variable 和 var,並不會分配給 let,const 和 function expression。

例如:

會 hoist 的情況

  • var
console.log(x); // undefined
var x = 10;
console.log(x); // 10

在程式碼被執行之前, JavaScript 會先找到 var ,再找到 x 這個變數,並放到記憶體裡面,但 assignment 這件事情先不管,所以當第 1 行 console.log(x) 時會看到 undefined,因為電腦已經知道 x 是個變數,但裡面還沒被做 assignment
接著執行第 2 行時,就做 assignment,把 10 放進 x 裡面,第 3 行 console.log(x) 就會看到 10 這個數字

  • function declaration
sayHi();
function sayHi(){
  console.log("Hi");
}
// Hi

在程式碼被執行之前, JavaScript 會先找到 sayHi 這個 function 並丟到記憶體裡面,當第 1 行被執行時,電腦會知道 sayHi 這個 function 裡面的東西,所以會出現 Hi 的結果

不會 hoist 的情況

  • lexical declaration(let & const)
console.log(x);
let x = 10;
// Uncaught ReferenceError: Cannot access 'x' before initialization
  • arrow function expression
sayHi();
const sayHi = ()=>{
  console.log("Hi");
}
// Uncaught ReferenceError:Cannot access 'sayHi' before initialization 

Scope(作用域)

  • Global Scope
    不管是 var,let 還是 const 只要放在最外層,都含有 global scope
let myName = "Helen";
function sayHi(){
  console.log("sayHi: " + myName);
  function sayHi2(){
    console.log("sayHi2: " + myName);
  }
  sayHi2(); // sayHi2: Helen
}
sayHi(); // sayHi: Helen

myName 是全域變數,在任何地方都是有意義的,所以無論在哪裡都可以找到 myName

  • function Scope
    無論是 var,let or const,他們如果在 function 中被宣告,就只能在 function 中被使用,離開了 function 就沒有意義了
function sayHi(){
  let myName = "Helen";
  console.log(myName);
}
sayHi(); // Helen
console.log(myName); // Uncaught ReferenceError: myName is not defined 
  • Block Scope
    let & const 只在迴圈和條件式中有意義
if(true){
  let x = 10;
  console.log(x); // 10
}
console.log(x); // Uncaught ReferenceError: x is not defined 

var 沒有 block scope,因此使用 var 會有很多問題

if(true){
  var x = 10;
  console.log(x); // 10
}
console.log(x); // 10

Closure and Scope Chaining

在 Creation phase 會發生的事情

let myName = "Helen";
function sayHi(){
  let myName = "Mary";
  console.log("sayHi: " + myName); 
  sayHi2();
}
function sayHi2(){
    console.log("sayHi2: " + myName); 
  }
sayHi();
// sayHi: Mary
// sayHi2: Helen

如果在 function 中的變數並沒有在 function 中被定義,則會跑去 function 被定義的地方找,function sayHi2 裡的 myName 並沒有在此 function 中被定義,所以會跑到 sayHi2 被定義的地方找(window),找到 myName 是 Helen

let myName = "Helen";
function sayHi(){
  let myName = "Mary";
  console.log(myName); // Mary
  
  function sayHi2(){
    console.log(myName); // Mary
  }
  
  function sayHi3(){
    let myname = "Lisa";
    sayHi2();
  }
  sayHi3()
}

sayHi();

sayHi3() 裡執行 sayHi2() 時,因為 sayHi2() 並沒有定義 myName,所以會跑到 sayHi2() 被定義的地方(sayHi()裡)找,最終找到 myName 是 Mary

Call Stack

Call Stack工具
在執行 calling function 時會產生 stack
stack 是一種資料結構,可以想像成容器的概念,後面進去的要先出來

function fn1(){
  console.log("This is fn1");
  
  fn2();
  function fn2(){
    console.log("This is fn2")
    
    fn3();
    function fn3(){
      console.log("This is fn3")
    }
    console.log("Running")
  }
  console.log("Done")
}
fn1();
// This is fn1
// This is fn2
// This is fn3
// Runnung
// Done

上一篇
Day 18 - for in & for of loop
下一篇
Day 20 - Constructor Function & Prototype
系列文
Be friend with JavaScript39

尚未有邦友留言

立即登入留言