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