[進階 js 05] hoisting(提升)


Posted by tzutzu858 on 2021-03-17

hoisting(提升)

直接看一個簡單的範例
什麼都不寫只寫下面這一行會發生什麼事

console.log(b)

這樣會輸出什麼?
他會輸出 b is not defined

那換成下面例子,照理來說應該還是 b is not defined

console.log(b)
var b = 10

但出來結果是 undefined
這現象就叫 hoisting(提升)
上面這段程式碼可以把他想成以下流程(但實際上不是這樣跑,只是比較好理解而已)

var b 
console.log(b)
b = 10

變數宣告會出現在第一行,拉上去的感覺,就叫 hoisting(提升)

只有宣告會提升,賦值不會


再一個例子

test()

function test() {
  console.log(123)  
}

這個例子可以成功輸出 123
宣告一個 function 之前就直接呼叫它
但在某些程式語言是做不到的


最後一個例子

test()

var test = function () {
  console.log(123)  
}

可能會以為跟剛剛的例子一樣都是可以成功輸出 123
但實際是 test is not a function

在上述例子可以把它拆成兩個
賦值和變數宣告
只有變數宣告可以 hoisting
所以執行看起來像下面這樣

var test
test()

test = function () {
  console.log(123)  
}

這樣執行 test() 就找不到 function


hoisting 的順序

hoisting 只會發生在它的 scope 裡面

下面程式 a 會印出什麼呢 ?

var a = 'global'
function test() {
    console.log(a)
    var a = 'local'
}

test ()

實際執行是 undefined

上面程式碼可以看成下面這樣
test 這個 scope 裡面的 var a = 'local' 被提升了

var a = 'global'
function test() {
    var a 
    console.log(a)
    a = 'local'
}

那如果再多一個 a 的 function , console.log(a)又會印出什麼?
hoisting 提升的順序又是什麼 ?

function test() {
    console.log(a)
    var a = 'local'
    function a () {

    }
}

出來會是 [Function: a]
改一下順序呢 ?

function test() {
    console.log(a)
    function a () {

    }
    var a = 'local'
}

test()

出來還是 [Function: a]

所以 hoisting 的順序 function 佔有優先權

那如果有同樣兩個 function 呢 ?

function test() {
    console.log(a)
    a()
    function a () {
        console.log(1)
    }

    function a () {
        console.log(2)
    }
    var a = 'local'
}

test()

結果是 2

代表比較後面宣告的會蓋掉前面的


下面例子會被蓋掉嗎?

function test(a) {
    console.log(a)
    var a = 456
}

test(123)

出來 a 還是 123 ,並沒有 hoisting 不會影響到 a 這個變數

那如果是同名的 function 呢 ?

function test(a) {
    console.log(a)
    function a () {

    }
}

test(123)

出來結果是 [Function: a]
被蓋過去了

所以如果是 function 就會被蓋過去


hoisting 優先順序

  1. function
  2. arguments 參數
  3. var

hoisting 的原理為何?從 ECMAScript 下手

可以先做一下,覺得 log 出來的值依序會是什麼 ?

var a = 1;
function test(){
  console.log('1.', a);
  var a = 7;
  console.log('2.', a);
  a++;
  var a;
  inner();
  console.log('4.', a);
  function inner(){
    console.log('3.', a);
    a = 30;
    b = 200;
  }
}
test();
console.log('5.', a);
a = 70;
console.log('6.', a);
console.log('7.', b);

答案

var a = 1;
function test(){
  console.log('1.', a); // undefined
  var a = 7;
  console.log('2.', a); // 7
  a++; // 8 
  var a;
  inner();
  console.log('4.', a); // 30
  function inner(){
    console.log('3.', a); // 8
    a = 30;
    b = 200;
  }
}
test();
console.log('5.', a); // 1
a = 70;
console.log('6.', a); // 70
console.log('7.', b); // 200

ECMAScript 是什麼 ?

可以把他當作 JavaScript 所 follow 的一個標準,可以把他當 JavaScript 的聖經
https://www.ecma-international.org/wp-content/uploads/ECMA-262_3rd_edition_december_1999.pdf
1999 年出版的第三版,對應比較舊的版本,但都差不多,從舊的版本看比較容易理解一點
ECMAScript 這樣描述

Execution Contexts
When control is transferred to ECMAScript executable code, control is entering an execution context. Active execution contexts logically form a stack. The top execution context on this logical stack is the running execution context.

下面這張圖就是 Execution Contexts 的概念

(來源:https://medium.freecodecamp.org/lets-learn-javascript-closures-66feb44f6a44)










Related Posts

[C#] Asp.net Mvc 使用 AntiForgery

[C#] Asp.net Mvc 使用 AntiForgery

Web Component 實戰

Web Component 實戰

MTR04_0927

MTR04_0927


Comments