摘要:在中,通過棧的存取方式來管理執行上下文,我們可稱其為執行棧,或函數調用棧。而處于棧頂的是當前正在執行函數的執行上下文,當函數調用完成后,它就會從棧頂被推出理想的情況下,閉包會阻止該操作,閉包后續文章深入詳解。
寫在開篇
已經不敢自稱前端小白,曾經吹過的牛逼總要一點點去實現。
正如前領導說的,自己喝酒吹過的牛皮,跪著都得含著淚去實現。
那么沒有年終完美總結,來個新年莽撞開始可好。
進擊巨人系列開篇,不忘初心,砥礪前行。
理解執行上下文執行上下文(Execution Context): 函數執行前進行的準備工作(也稱執行上下文環境)
運行JavaScript代碼時,當代碼執行進入一個環境時,就會為該環境創建一個執行上下文,它會在你運行代碼前做一些準備工作,如確定作用域,創建局部變量對象等。
具體做了什么先按下不表,先來看下JavaScript執行環境有哪些?
JavaScript中執行環境全局環境
函數環境
eval函數環境 (已不推薦使用)
那么與之對應的執行上下文類型同樣有3種:
執行上下文的類型全局執行上下文
函數執行上下文
eval函數執行上下文
JavaScript運行時首先會進入全局環境,對應會生成全局上下文。程序代碼中基本都會存在函數,那么調用函數,就會進入函數執行環境,對應就會生成該函數的執行上下文。
先插播一個知識點:"JS是單線程"! "單線程"! "單線程"!
簡單理解下單線程,就是同個時間段只能做一件任務,完成之后才可以繼續下一個任務。正如女朋友只有一個,各位面向對象的小伙伴們你們說對不對?有女票的必須說沒毛病。
既然是這樣,必須要有一個排隊機制,不然就會出現幾個流氓霸著車道不讓過,"還有王法么?"
JS中管理多個執行上下文函數編程中,代碼中會聲明多個函數,對應的執行上下文也會存在多個。在JavaScript中,通過棧的存取方式來管理執行上下文,我們可稱其為執行棧,或函數調用棧(Call Stack)。
在說明執行棧前,先來補下"棧數據結構"知識點。
棧數據結構
借助前端大神的例子,用乒乓球盒子來理解棧的存取方式。(這個例子讓我徹底記住了棧數據結構)
棧遵循"先進后出,后進先出"的規則,或稱LIFO ("Last In First Out") 規則。
如圖所示,我們只能從棧頂取出或放入乒乓球,最先放進盒子的總是最后才能取出。
棧中"放入/取出",也可稱為"入棧/出棧"。
總結棧數據結構的特點:
后進先出,先進后出
出口在頂部,且僅有一個
執行棧(函數調用棧)理解完棧的存取方式,我們接著分析JavaScript中如何通過棧來管理多個執行上下文。
程序執行進入一個執行環境時,它的執行上下文就會被創建,并被推入執行棧中(入棧);
程序執行完成時,它的執行上下文就會被銷毀,并從棧頂被推出(出棧),控制權交由下一個執行上下文。
因為JS執行中最先進入全局環境,所以處于"棧底的永遠是全局環境的執行上下文"。而處于"棧頂的是當前正在執行函數的執行上下文",當函數調用完成后,它就會從棧頂被推出(理想的情況下,閉包會阻止該操作,閉包后續文章深入詳解)。
"全局環境只有一個,對應的全局執行上下文也只有一個,只有當頁面被關閉之后它才會從執行棧中被推出,否則一直存在于棧底"
文字太多不如上代碼系列 ——》代碼 + 圖,一覽無遺:
function foo () { function bar () { return "I am bar"; } return bar(); } foo();執行上下文的生命周期
執行上下文的生命周期有兩個階段:
創建階段(進入執行上下文)
執行階段(代碼執行)
創建階段:函數被調用時,進入函數環境,為其創建一個執行上下文,此時進入創建階段
執行階段:執行函數中代碼時,此時執行上下文進入執行階段
創建階段的操作
創建變量對象
函數環境會初始化創建Arguments對象(并賦值)
函數聲明(并賦值)
變量聲明,函數表達式聲明(未賦值)
確定this指向(this由調用者確定)
確定作用域(詞法環境決定,哪里聲明定義,就在哪里確定)
執行階段的操作
變量對象賦值
變量賦值
函數表達式賦值
調用函數
順序執行其它代碼
看到這里,我們不經會問變量對象是什么鬼,它與代碼中常見的函數聲明,變量聲明有神馬關系???
變量對象和活動對象的區別:當進入到一個執行上下文后,這個變量對象才會被激活,所以叫活動對象(AO),這時候活動對象上的各種屬性才能被訪問。
"創建階段對函數聲明做賦值,變量及函數表達式僅做聲明,真正的賦值操作要等到執行上下文代碼執行階段"。
代碼例子1:變量提升
function foo() { console.log(a); // 輸出undefined var a = "I am here"; // 賦值 } foo(); // 實際執行過程 function foo() { var a; // 變量聲明,var初始化undefined console.log(a); a = "I am here"; // 變量重新賦值 }
代碼例子2:函數聲明優先級
function foo() { console.log(bar); var bar = 20; function bar() { return 10; } var bar = function() { return 30; } } foo(); // 輸出bar()整個函數聲明函數聲明,變量聲明,函數表達式的優先級
函數聲明,如果有同名屬性,會替換掉
變量,函數表達式
函數聲明優先 > 變量,函數表達式
執行上下文的數量限制(堆棧溢出)執行上下文可存在多個,雖然沒有明確的數量限制,但如果超出棧分配的空間,會造成堆棧溢出。常見于遞歸調用,沒有終止條件造成死循環的場景。
// 遞歸調用自身 function foo() { foo(); } foo(); // 報錯: Uncaught RangeError: Maximum call stack size exceeded文末總結
JavaScript是單線程
棧頂的執行上下文處于執行中,其它需要排隊
全局上下文只有一個處于棧底,頁面關閉時出棧
函數執行上下文可存在多個,但應避免遞歸時堆棧溢出
函數調用時就會創建新的上下文,即使調用自身,也會創建不同的執行上下文
參考文檔:
執行上下文詳細圖解
理解JavaScript 中的執行上下文和執行棧
這一次,徹底弄懂 JavaScript 執行機制
本文首發Github,期待Star!
https://github.com/ZengLingYong/blog
作者:以樂之名
本文原創,有不當的地方歡迎指出。轉載請指明出處。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101009.html
摘要:中有三種數據結構棧堆隊列。前端進擊的巨人一執行上下文與執行棧,變量對象中解釋執行棧時,舉了一個乒乓球盒子的例子,來演示棧的存取方式,這里再舉個栗子搭積木。對于基本類型,棧中存儲的就是它自身的值,所以新內存空間存儲的也是一個值。 面試經常遇到的深淺拷貝,事件輪詢,函數調用棧,閉包等容易出錯的題目,究其原因,都是跟JavaScript基礎知識不牢固有關,下層地基沒打好,上層就是豆腐渣工程,...
摘要:進擊的巨人第三篇,本篇就作用域作用域鏈閉包等知識點,一一擊破。在此我們遵照的方式,暫且稱是閉包。所以,一名合格的前端,除了會用閉包,還要正確的解除閉包引用。 進擊的巨人第三篇,本篇就作用域、作用域鏈、閉包等知識點,一一擊破。 showImg(https://segmentfault.com/img/bVburWd?w=1280&h=854); 作用域 作用域:負責收集并維護由所有聲明的...
摘要:自執行函數閉包實現模塊化以樂之名程序員產品經理對作用域,以及閉包知識還沒掌握的小伙伴,可回閱前端進擊的巨人三從作用域走進閉包。參考文檔利用閉包實現模塊化翻譯淺談中的高階函數系列更文請關注專欄前端進擊的巨人,不斷更新中。。。 系列更文前三篇文章,圍繞了一個重要的知識點:函數。函數調用棧、函數執行上下文、函數作用域到閉包。可見不理解函數式編程,代碼都擼不好。 showImg(https:/...
摘要:有關函數柯里化的詳解,請回閱前端進擊的巨人五學會函數柯里化。構造函數中的通過操作符可以實現對函數的構造調用。在了解構造函數中的前,有必要先了解下實例化對象的過程。 showImg(https://segmentfault.com/img/bVburMp?w=800&h=600); 常見this的誤解 指向函數自身(源于this英文意思的誤解) 指向函數的詞法作用域(部分情況) th...
摘要:隆重請出主角防抖與節流。防抖與節流的異同相同都是防止某一時間段內,函數被頻繁調用執行,通過時間頻率控制,減少回調函數執行次數,來實現相關性能優化。參考文章分鐘理解的節流防抖及使用場景函數防抖和節流 showImg(https://segmentfault.com/img/bVburM8?w=800&h=600); 本篇課題,或許早已是爛大街的解讀文章。不過春招系列面試下來,不少伙伴們還...
閱讀 1309·2021-09-27 13:56
閱讀 2339·2019-08-26 10:35
閱讀 3497·2019-08-23 15:53
閱讀 1849·2019-08-23 14:42
閱讀 1233·2019-08-23 14:33
閱讀 3562·2019-08-23 12:36
閱讀 1947·2019-08-22 18:46
閱讀 996·2019-08-22 14:06