iT邦幫忙

2021 iThome 鐵人賽

DAY 30
0
Modern Web

前端幼鳥三十天養成記系列 第 30

預編譯 - 變數和function的被建立、初始化/預編譯、執行的全紀錄

  • 分享至 

  • xImage
  •  

你以為JS拿來就乖乖照著我們打的一行一行跑嗎?太天真了,我說我~~
變數怎麼存,存哪裡,在哪裡叫得到變數出來?我們會連續幾天,討論這個問題~

預編譯

一句話解釋,預編譯是幹蛤的?
根據宣告變數、宣告function的關鍵字,在內存開闢位置給變數、function

預編譯發生在何時?

執行前一刻,做預編譯:

  • 執行全域前一刻,做全域的預編譯
  • 執行function前一刻,做function的預編譯。

function scope內部的預編譯的編譯順序

  1. 建立形參(形式參數)、
    建立變數

    特別注意:形參var 初始化undefined;letconst沒有初始化

  2. 賦值實參(實際參數)給形參

  3. 建立function(此時不管function的body是甚麼,執行時才看)

  4. 開始執行(function變數這裡才賦值)

巢狀function的建立、預編譯、執行 Rundown - 是不是很像俄羅斯娃娃

ornament-g86a0c122a_1920.jpg

圖片作者:https://pixabay.com/zh/users/schwoaze-4023294/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=3131097"

各functionScope預編譯的時間軸.png

function outerFun(){
	function innerFun(){};
	innterFun();
};
outerFun();
  • window object在預編譯的step4:宣告function時,建立了outerFun
  • window object執行
  • window object執行中,執行到outerFun()時:
    • 執行outerFun代碼的前一刻,預編譯outerFun
      • 預編譯outerFun時,建立了innerFun
    • outerFun執行
    • outerFun執行中,執行到innerFun()時:
      • 執行innerFun代碼的前一刻,預編譯innerFun
      • innerFun執行

整理一下邏輯:

  • 預編譯發生在執行之前
  • 預編譯時會建立變數、function

試問:執行時,我愛多早呼叫變數、呼叫function,愛多早就多早,不會報錯,頂多undefined?
是的呀~~因為我已經把宣告變數、宣告function這件事情,提升了嘛~

提升(Hoisting)

(這裡也還不是提升的完整版
受限於let有一丟丟的麻煩,這裡只先討論var變數和function
一定會有完整版的放心~~)

  • var變數的提升:undefined

    • 取值時,發生在「變數本人被建立,初始undefined後,賦值前」
    • var的預編譯有初始化undefined

    →故:var變數的提升,得undefined

  • function的提升:完整的function(不是空殼function)

    • 發生在「function本人被建立,(執行function前必須的)預編譯完成之後」
      換句話說就是「function執行時」
      從「要呼叫function,function一定正在執行阿~」的觀點也很合理
  • 小整理:var變數、function甚麼時後有值的(可以往上對照俄羅斯娃娃那裏)

    • var要撇除stack內存的初始值(undefined),須等到有人對他賦值
    • function
      • 建立時,stack內存的值,由heap內存提供function的地址
      • function要有內變數、內層function,須等到function自己進行預編譯時

內存stack and heap.png

猜猜:是不是用原始值引用值來區分能不能完整提升?

.

.

.

.

.

.

想多了(我就是這樣誤以為)

object,array都是引用值的一種,但他們就不像function object可以整塊完整被提升。

console.dir(o) //undefined
console.dir(b) //undefined
console.dir(f) //f()
var o={
    'name':'小o',
    '白花':'可曾枯萎呀'
}
var b=['輕聲唱著','少年的模樣','會悲傷會幻想']
function f(){
    var name='別去打擾她'
}

//部分歌詞:<<旅行家說>> 毛不易 

至於為甚麼只有function可以有這個好康,平平都是引用值,為甚麼object和array沒有呢?
我個人的想像是,因為var變數的作用域(有效範圍)是以function為界,所以才會以function做為單位進行提升。

也不是所有function都會乖乖地提升,那到底是誰怎麼不乖呢?要拜乖乖?

function 預編譯:函數聲明 vs 函數表達式

fun1();  //1
fun2();  //Uncaught TypeError: fun2 is not a function

//function聲明
function fun1(){console.log(1)};
//function表達式
var fun2=function(){console.log(2)}; 

function表達式雖然提升失敗,被說fun2不是一個function不被承認QQ
但並沒有破壞規則,規則還是原本那個規則喔~~來,上原因

GO{
	fun1 : function fun1(){......},
	fun2 : undefined
}

沒錯,因為他電腦看到var fun2=,就覺得他是一個原始值,不是function引用值
殊不知後面等於一個function。失算失算

小結論:能不能像function宣告完整被提升的關鍵因素,是function關鍵字


上一篇
樣式屬性
系列文
前端幼鳥三十天養成記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言