日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

大话javascript 2期:执行上下文与执行上下文栈

發布時間:2023/12/20 javascript 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 大话javascript 2期:执行上下文与执行上下文栈 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、什么是執行上下文?

執行上下文(Execution Context): 函數執行前進行的準備工作(也稱執行上下文環境)

JavaScript在執行一個“代碼段”之前,即解析(預處理)階段,會先進行一些“準備工作”,例如掃描JS中var定義的變量、函數名等,進而生成執行上下文。

name-
變量對象(VO, variable object)當前函數定義的變量、函數、參數
作用域鏈(Scope chain)源代碼定義時形成的作用域鏈
this

JS中的“代碼段”分為三種:全局代碼段、函數體代碼段、eval代碼段。(注:ES6之前,JS不存在“代碼塊”作用域的概念,即除了函數之外所有“{}”里的代碼,都屬于全局作用域)

全局代碼段“準備工作”包括:

1.變量、函數表達式 —— 變量聲明,默認賦值為undefined; 2.this —— 賦值; 3.函數聲明 —— 賦值。

函數體代碼段“準備工作”包括:

1.變量、函數表達式 —— 變量聲明,默認賦值為undefined; 2.this —— 賦值; 3.函數聲明 —— 賦值; 4.參數 —— 賦值; 5.argument —— 賦值; 6.自由變量的取值作用域 —— 賦值。

evel()不推薦使用,所以不再分析evel代碼段。

至此,“執行上下文”的定義可以通俗化為 —— 在執行代碼段之前(預處理階段),把將要用到的所有變量都事先拿出來,有的直接賦值,有的先用undefined占個空,這些變量共同組成的詞法環境,即為執行上下文環境。

二、執行上下文棧

javaScript是單線程語言,簡單理解下單線程,就是同個時間段只能做一件任務,完成之后才可以繼續下一個任務。
函數編程中,代碼中會聲明多個函數,對應的執行上下文也會存在多個。在JavaScript中,通過棧的存取方式來管理執行上下文,我們可稱其為執行棧,或函數調用棧(Call Stack)。

1.棧數據結構

要簡單理解棧的存取方式,我們可以通過類比乒乓球盒子來分析。如下圖左側。

棧遵循"先進后出,后進先出"的規則,或稱LIFO ("Last In First Out") 規則。

如圖所示,我們只能從棧頂取出或放入乒乓球,最先放進盒子的總是最后才能取出。
棧中"放入/取出",也可稱為"入棧/出棧"。

總結棧數據結構的特點:

  • 后進先出,先進后出
  • 出口在頂部,且僅有一個

2.執行上下文棧ECS(Execution Context Stack)(函數調用棧)

程序執行進入一個執行環境時,它的執行上下文就會被創建,并被推入執行棧中(入棧);
程序執行完成時,它的執行上下文就會被銷毀,并從棧頂被推出(出棧),控制權交由下一個執行上下文。

因為JS執行中最先進入全局環境,所以處于"棧底的永遠是全局環境的執行上下文"。而處于"棧頂的是當前正在執行函數的執行上下文",當函數調用完成后,它就會從棧頂被推出(理想的情況下,閉包會阻止該操作,閉包后續文章深入詳解)。

"全局環境只有一個,對應的全局執行上下文也只有一個,只有當頁面被關閉之后它才會從執行棧中被推出,否則一直存在于棧底"

function foo () {function bar () {return 'I am bar';}return bar(); } foo();

3.執行上下文的生命周期

執行上下文的生命周期有兩個階段:

  • 創建階段(進入執行上下文)
  • 執行階段(代碼執行)
  • 創建階段:函數被調用時,進入函數環境,為其創建一個執行上下文,此時進入創建階段
    執行階段:執行函數中代碼時,此時執行上下文進入執行階段

    創建階段的操作

  • 創建變量對象

    • 函數環境會初始化創建Arguments對象(并賦值)
    • 函數聲明(并賦值)
    • 變量聲明,函數表達式聲明(未賦值)
  • 確定this指向(this由調用者確定)
  • 確定作用域(詞法環境決定,哪里聲明定義,就在哪里確定)
  • 執行階段的操作

  • 變量對象賦值

    • 變量賦值
    • 函數表達式賦值
  • 2.調用函數
    3.順序執行其它代碼

    變量對象和活動對象的區別:

    當進入到一個執行上下文后,這個變量對象才會被激活,所以叫活動對象(AO),這時候活動對象上的各種屬性才能被訪問。

    "創建階段對函數聲明做賦值,變量及函數表達式僅做聲明,真正的賦值操作要等到執行上下文代碼執行階段"。

    代碼例子1:變量提升

    function foo() {console.log(a); // 輸出undefinedvar a = 'I am here'; // 賦值 } foo();

    // 實際執行過程

    function foo() {var a; // 變量聲明,var初始化undefinedconsole.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()整個函數聲明

    函數聲明,變量聲明,函數表達式的優先級

  • 函數聲明,如果有同名屬性,會替換掉
  • 變量,函數表達式
  • 函數聲明優先 > 變量,函數表達式
  • 4.執行上下文的數量限制(堆棧溢出)

    執行上下文可存在多個,雖然沒有明確的數量限制,但如果超出棧分配的空間,會造成堆棧溢出。常見于遞歸調用,沒有終止條件造成死循環的場景。 // 遞歸調用自身 function foo() {foo(); } foo();// 報錯: Uncaught RangeError: Maximum call stack size exceeded

    三、執行上下文流程圖

    總結

    以上是生活随笔為你收集整理的大话javascript 2期:执行上下文与执行上下文栈的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。