摘要:函數(shù)和變量相比,會被優(yōu)先提升。這意味著函數(shù)會被提升到更靠前的位置。僅提升聲明,而不提升初始化。
JavaScript 函數(shù)高級——執(zhí)行上下文與執(zhí)行上下文棧(圖解+典型實例分析) 變量提升與函數(shù)提升
變量聲明提升
通過 var 定義(聲明)的變量,在定義語句之前就可以訪問到
值:undefined
/* 面試題 : 輸出 undefined */ var a = 3 function fn() { console.log(a) // undefined 調(diào)用fn()后進入函數(shù)體內(nèi)部,通過 var 聲明的變量提升,值為undefined var a = 4 console.log(a) // 4 } fn() console.log("----")
可以用開發(fā)工具的代碼調(diào)試工具設置斷點,清楚地看到a的值的變化。
函數(shù)聲明提升
通過 function 聲明的函數(shù),在該函數(shù)聲明之前就可以直接調(diào)用
值:函數(shù)定義(對象)
console.log(b) // undefined 通過 var 聲明的變量b 變量聲明提升 fn2() // fn2() 通過 function 聲明的函數(shù)fn2 函數(shù)聲明提升 fn3() // 報錯 通過 var 聲明的函數(shù)fn3 變量聲明提升 var b = 3 function fn2() { console.log("fn2()") } var fn3 = function () { console.log("fn3()") }
!!注意 var a = 3, var fn = function(){ }只要是var聲明的,都是變量聲明提升,值都是undefined
??!注意:var fn = function(){ }屬于變量聲明提升,不是函數(shù)聲明提升
問題:變量提升和函數(shù)提升是如何產(chǎn)生的?
這是因為在JavaScript中執(zhí)行上下文的工作方式造成的。
函數(shù)和變量相比,會被優(yōu)先提升。這意味著函數(shù)會被提升到更靠前的位置。
JavaScript 僅提升聲明,而不提升初始化。
執(zhí)行上下文個數(shù) = n(調(diào)用的函數(shù)個數(shù)) + 1(全局執(zhí)行上下文)
// 變量聲明提升,函數(shù)聲明提升,全局代碼的函數(shù)和方法添加為Window的方法和屬性 console.log(a1, window.a1) // undefined undefined window.a2() // a2() console.log(this) // Window var a1 = 3 function a2() { console.log("a2()") } console.log(a1) // 3代碼分類(位置)
全局代碼
函數(shù)代碼
全局執(zhí)行上下文在執(zhí)行全局代碼前將window確定為全局執(zhí)行上下文
對全局數(shù)據(jù)進行預處理:
var 定義的全局變量==>undefined,添加為window屬性
function 聲明的全局函數(shù)==>賦值(fun),添加為window的方法
this==>賦值(window)
開始執(zhí)行全局代碼
函數(shù)執(zhí)行上下文在調(diào)用函數(shù),準備執(zhí)行函數(shù)體之前,創(chuàng)建對應的函數(shù)執(zhí)行上下文對象
對局部數(shù)據(jù)進行預處理
形參變量==>賦值(實參)==>添加為執(zhí)行上下文的屬性
arguments==>賦值(實參列表),添加為執(zhí)行上下文的屬性
var 定義的局部變量==>undefined==>添加為執(zhí)行上下文的屬性
function聲明的函數(shù)==>賦值(fun)==>添加為執(zhí)行上下文的屬性
this==>賦值(調(diào)用函數(shù)的對象)
開始執(zhí)行函數(shù)體代碼
執(zhí)行上下文棧 理解在全局代碼執(zhí)行前, JS引擎就會創(chuàng)建一個棧來存儲管理所有的執(zhí)行上下文對象
在全局執(zhí)行上下文(window)確定后, 將其添加到棧中(壓棧)
在函數(shù)執(zhí)行上下文創(chuàng)建后, 將其添加到棧中(壓棧)
在當前函數(shù)執(zhí)行完后,將棧頂?shù)膶ο笠瞥?出棧)
當所有的代碼執(zhí)行完后, 棧中只剩下window
流程分析// 1. 進入全局上下文 var a = 10 var bar = function (x) { var b = 5 // 3. 進入foo執(zhí)行上下文 foo(x + b) } var foo = function (y) { var c = 5 console.log(a + c + y) } // 2. 進入bar函數(shù)執(zhí)行上下文 bar(10) // 30
用斷點調(diào)試工具查看執(zhí)行上下文調(diào)用棧
面試題 題1:遞歸調(diào)用的執(zhí)行上下文console.log("gb: " + i) var i = 1 foo(1) function foo(i) { if (i == 4) { return } console.log("fb:" + i) foo(i + 1) //遞歸調(diào)用: 在函數(shù)內(nèi)部調(diào)用自己 console.log("fe:" + i) } console.log("ge: " + i) // ge:1
依次輸出什么?
整個過程中產(chǎn)生了幾個執(zhí)行上下文?
5個 = 4個函數(shù)執(zhí)行上下文 + 1個全局執(zhí)行上下文
調(diào)試查看:
console.log(foo) // ? foo() {console.log("函數(shù)聲明")} console.log(foo()) // 我是一個函數(shù) undefined function foo() { console.log("我是一個函數(shù)") } var foo = 3 console.log(foo) // 3 console.log(foo()) // foo is not a function
相當于
function foo(){ console.log("函數(shù)聲明") } // 函數(shù)聲明先提升 var foo // 變量聲明提升,變量初始化未提升,此時foo的值為undefined,所以不會覆蓋函數(shù)聲明 console.log(foo) // 打印出? foo() {console.log("函數(shù)聲明")} console.log(foo()) // 我是一個函數(shù) undefined foo = 3 // 此時給foo賦值為3,則會覆蓋前面的 console.log(foo) // 3 console.log(foo()) // foo is not a function,因為此時foo=3題3:考察全局環(huán)境下的變量提升
if (!(t in window)) { var t = 1 } console.log(t) // undefined
t in window // true
原因就在于變量t被提升到了全局環(huán)境最頂部,通過關(guān)鍵字var在全局作用域中聲明的變量將作為全局對象(window)的一個屬性,上面的代碼JavaScript其實是這樣解析的:
var t if (!(t in window)) { var t = 1 } console.log(t) // undefined題4(好題)
var c = 1 function c(c) { console.log(c) var c = 3 } c(2) // 報錯 c is not a function
注意:函數(shù)提升為c(),整個函數(shù)提升,所以上面的代碼相當于下面這樣,這樣就很清楚了吧!
function c(c) { console.log(c) var c = 3 } var c c = 1 c(2) //所以 c is not a function
函數(shù)體內(nèi)的代碼根本就沒機會執(zhí)行。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/104157.html
摘要:因此,所有在方法中定義的變量都是放在棧內(nèi)存中的當我們在程序中創(chuàng)建一個對象時,這個對象將被保存到運行時數(shù)據(jù)區(qū)中,以便反復利用因為對象的創(chuàng)建成本通常較大,這個運行時數(shù)據(jù)區(qū)就是堆內(nèi)存。 上一篇:《javascript高級程序設計》筆記:繼承近幾篇博客都會圍繞著圖中的知識點展開 showImg(https://segmentfault.com/img/bVY0C4?w=1330&h=618);...
摘要:本計劃一共期,每期重點攻克一個面試重難點,如果你還不了解本進階計劃,點擊查看前端進階的破冰之旅本期推薦文章深入之執(zhí)行上下文棧和深入之變量對象,由于微信不能訪問外鏈,點擊閱讀原文就可以啦。 (關(guān)注福利,關(guān)注本公眾號回復[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實戰(zhàn)、面試指導) 本周正式開始前端進階的第一期,本周的主題是調(diào)用堆棧,今天是第二天。 本計劃一共28期,每期...
摘要:首次運行代碼時,會創(chuàng)建一個全局執(zhí)行上下文并到當前的執(zhí)行棧中。執(zhí)行上下文的創(chuàng)建執(zhí)行上下文分兩個階段創(chuàng)建創(chuàng)建階段執(zhí)行階段創(chuàng)建階段確定的值,也被稱為。 (關(guān)注福利,關(guān)注本公眾號回復[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實戰(zhàn)、面試指導) 本周正式開始前端進階的第一期,本周的主題是調(diào)用堆棧,,今天是第一天 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進...
摘要:進階期理解中的執(zhí)行上下文和執(zhí)行棧進階期深入之執(zhí)行上下文棧和變量對象但是今天補充一個知識點某些情況下,調(diào)用堆棧中函數(shù)調(diào)用的數(shù)量超出了調(diào)用堆棧的實際大小,瀏覽器會拋出一個錯誤終止運行。 (關(guān)注福利,關(guān)注本公眾號回復[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實戰(zhàn)、面試指導) 本周正式開始前端進階的第一期,本周的主題是調(diào)用堆棧,今天是第3天。 本計劃一共28期,每期重點攻...
摘要:使用上一篇文章的例子來說明下自由變量進階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數(shù),也不是局部變量,所以是自由變量。 (關(guān)注福利,關(guān)注本公眾號回復[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實戰(zhàn)、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第7天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計...
閱讀 2193·2021-11-19 09:55
閱讀 2657·2021-11-11 16:55
閱讀 3187·2021-09-28 09:36
閱讀 1954·2021-09-22 16:05
閱讀 3289·2019-08-30 15:53
閱讀 1815·2019-08-30 15:44
閱讀 2907·2019-08-29 13:10
閱讀 1351·2019-08-29 12:30