国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

一段代碼,帶你理解js執行上下文的工作流程

developerworks / 3423人閱讀

摘要:由于函數被調用了,線程會從剛剛保存的變量中取出內容,去解析執行它。最后,當線程遇到離開上下文的標識,便離開上下文,并把的結果一并返回出去。

原文鏈接,歡迎關注我的博客

我相信很多前端初學者一開始都會被執行上下文這個概念弄暈,或者說似懂非懂。對于工作兩年的我來說,說來實在慚愧,雖然知道它大概是什么,但總覺得沒有一個更為清晰的認識(無法把它的工作過程描述清楚),因此最近特意溫習了一遍,寫下了這篇文章

執行上下文

要說清它的大體工作流程,需要提前說明三個基本概念,分別是thread of exection(線程)variable envirnoment(變量環境)call Stack(調用棧),這些概念我們或多或少接觸過,接下來我會通過一段示例代碼,和一系列圖片,進一步解釋這三個概念在執行上下文的運作流程。

一段代碼
const num = 2;

function addOne(input) {
  const output = input + 1;
  return output;
}

const result = addOne(2);
這段代碼做了什么

在運行上面這些代碼前,js 引擎做的第一件是就是創建一個global execution context,也就是全局執行上下文:


先看圖中的黑色箭頭,它表示線程thread的執行順序,眾所周知 js 是單線程的,它會一行行、從上往下去執行代碼;而右邊的global memory,它用于存儲當前上下文中的數據,由于線程目前處于全局上下文環境,故加了個global的前綴。

在這段代碼中,第一行我們聲明了一個名為num的不可變變量,并賦值為4, 因此global memory中就會分配內存,存儲這個變量:


接著繼續,當線程執行到第二行時,問題就來了:我們創建了一個addOne的變量,并把一個函數賦值于它,那在global memory里,到底存的是個啥?為了解答這個問題,我特意打印了一下:

function addOne(input) {
  const output = input + 1;
  return output;
}
console.log(addOne);


看,我們竟然把函數里的內容完完整整打印出來了,很明顯,它存的是一個函數內部的“文本信息”。

其實很容易理解,當執行第二行的時候,該函數并沒有被調用,因此線程不會立刻解析里面的內容,而是把它內部的信息以“文本內容”的形式保存下來,當需要執行的時候,才去解析變量里的函數內容,這也很好地解析了為什么函數內的異常僅會在函數被調用時才拋出來。

因此這時global execution context長這樣:


由于addOne里保存的是函數內容,目前對于線程而言它是未知的,因此我們這里特意用一個帶有輸入輸出箭頭的函數圖標,代表它是一個未被解析的函數。

我們繼續執行第三步:還是創建了一個變量result,但此時它被賦予undefined,因為線程暫時無法從addOne這個函數里獲知它的返回值。


由于addOne函數被調用了,線程會從剛剛保存的addOne變量中取出內容,去解析、執行它。這時 js 就創建了一個新的執行上下文——local execution context,即當前的執行上下文,這是一個船新的上下文,因此我特意用一個新圖片去描述它:


首先這個memory我加了個local前綴,表面當前存儲的都是此上下文中的變量數據。無論是上述的global memory,亦或是現在、或未來的local memory,我們可以用一個更為專業的術語variable envirnoment去描述這種存儲環境。

此外,這個黑箭頭我特意畫了個拐角,意味它是從全局上下文進來的,local memory首先會分配內存給變量input,它在調用時就被2賦值了,緊接著又創建了一個output標簽并把計算結果3賦值給它。最后,當線程遇到離開上下文的標識——return,便離開上下文,并把ouput的結果一并返回出去。

此時,這個上下文就沒用了(被執行完了),于是乎垃圾回收便盯上了它,選擇一個恰當的時機把里面的local memory刪光光。

這時候有同學會問道:你這個只是普通場景,那閉包怎么解釋呢?

其實閉包是個比較大的話題,這里也可以簡單描述下:return的是一個函數的話,它返回的不僅是函數本身,還會把local memory中被引用的變量作為此函數的附加屬性一并返回出去,這就好比印魚喜歡吸附在鯊魚身上一般,鱔魚無論去哪都帶著它,因此,無論這個函數在哪里被調用,它都能在它本身附帶的local memory中找到那個變量。如果你把返回的函數console.log出來,也是能夠找到它的,這里就不詳說,關于閉包的更多概念(包括在函數式編程中的使用),有興趣的童鞋可以看看這篇文章:Partial & Curry - 函數式編程

go on,回到了global execution contextresult不再孤零零地undefined,而是拿到了可愛的3:

到這里,我們的線程就完成了所有工作,可以歇息了,等等.....好像漏了什么沒講.....對,就是Call Stack

剛剛我們全篇在講解thread of exection多么努力地一行行解析執行代碼,variable envirnoment多么勤快地存儲變量,那call stack干了什么?是在偷懶嗎?

其實并不是,call stack起到了非常關鍵的作用:有了它,線程隨時可以知道自己目前處于哪個上下文。

試想一下,我們在寫代碼的過程中往往喜歡在各種函數內穿插著各種子函數,比如遞歸,因此勤勞的線程就得不斷地進入上下文、退出上下文、再進入、再進入、再退出、再進入,久而久之線程根本就不知道自己處于哪個上下文中,也不知道應該在哪個memory中取數據,全都亂套了,因此必須通過一種方式去跟蹤、記錄目前線程所處的環境。

call stack就是一種數據結構,用于“存儲”上下文,通過不斷推入push、推出pop上下文的方式,跟蹤線程目前所處的環境——線程無需刻意記住自己身處何方,只要永遠處于最頂層執行上下文,就是當前函數執行的正確位置

程序一開始運行的時候,call stack先會pushglobal execution context:

接著我們在上述代碼第三行調用了addOnecall stack立刻將addOne的上下文push進去,待執行到return標識后,再pop出來:


同樣的,即使在復雜的情況,只要遵循pushpop以及時刻處于最頂層上下文的原則,線程就可以一直保持在正確的位置上:


值得一提的是,call stack層數是有上限的,因此稍加不注意,你寫的遞歸可能會造成棧溢出了。

總結

簡單來說,上下文就是個可以用于執行代碼的環境,與它相關的有三個重要的概念:

thread of exection(執行線程) 它的主要職責是,從上到下,一行一行地解析和執行代碼,不會同時多處執行,也就是我們常掛在嘴邊的“js 是單線程的啦”

variable envirnoment(變量環境) 活躍的用于存儲數據的內存

call stack(調用棧) 一種用于存儲上下文,跟蹤當前線程所屬的上下文位置的數據結構

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105623.html

相關文章

  • 【進階1-4期】JavaScript深入之帶你走進內存機制

    摘要:引擎對堆內存中的對象進行分代管理新生代存活周期較短的對象,如臨時變量字符串等。內存泄漏對于持續運行的服務進程,必須及時釋放不再用到的內存。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第4天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計劃...

    不知名網友 評論0 收藏0
  • 【進階1-2期】JavaScript深入之執行下文棧和變量對象

    摘要:本計劃一共期,每期重點攻克一個面試重難點,如果你還不了解本進階計劃,點擊查看前端進階的破冰之旅本期推薦文章深入之執行上下文棧和深入之變量對象,由于微信不能訪問外鏈,點擊閱讀原文就可以啦。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第二天。 本計劃一共28期,每期...

    Richard_Gao 評論0 收藏0
  • 一篇文章帶你理解閉包

    摘要:通過例子再來回顧一下閉包的理解所謂的閉包就是可以創建一個獨立的環境,每個閉包里面的環境都是獨立的,互不干擾。此時就是一個閉包,這樣寫有些麻煩,我們對此改進一下。參考文章初識中的閉包從閉 走在前端的大道上 本篇將自己讀過的相關 javascript閉包 文章中,對自己有啟發的章節片段總結在這(會對原文進行刪改),會不斷豐富提煉總結更新。 首先著重回顧一下 全局變量 和 局部變量 全局變...

    bluesky 評論0 收藏0
  • 帶你玩轉prefetch, preload, dns-prefetch,defer和async

    摘要:緊接著發現,于是又停了,瀏覽器下載并執行完,繼續。,發現,遂將中文字展示了出來。的執行時間是在所有元素解析完成之后,事件觸發之前。的執行時間是在當前腳本下載完成后,所以多個是執行順序是不固定的。至此,完美的結構出爐了。 現代瀏覽器性能優化-JS篇 眾所周知,JS的加載和執行會阻塞瀏覽器渲染,所以目前業界普遍推薦把script放到之前,以解決js執行時找不到dom等問題。但隨著現代瀏覽器...

    godiscoder 評論0 收藏0
  • 帶你玩轉prefetch, preload, dns-prefetch,defer和async

    摘要:緊接著發現,于是又停了,瀏覽器下載并執行完,繼續。,發現,遂將中文字展示了出來。的執行時間是在所有元素解析完成之后,事件觸發之前。的執行時間是在當前腳本下載完成后,所以多個是執行順序是不固定的。至此,完美的結構出爐了。 現代瀏覽器性能優化-JS篇 眾所周知,JS的加載和執行會阻塞瀏覽器渲染,所以目前業界普遍推薦把script放到之前,以解決js執行時找不到dom等問題。但隨著現代瀏覽器...

    lewif 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<