目錄
作用域
作用域鏈
執行環境
#程式碼最佳化
首頁 web前端 js教程 javascript 作用域鏈與執行環境

javascript 作用域鏈與執行環境

Mar 26, 2017 pm 04:49 PM

作用域、作用域鏈、執行環境、執行環境堆疊以及this的概念在javascript中非常重要,本人經常混淆,這裡梳理一下;

  1. 局部作用域函數內部的區域,全域作用域就是window;

  2. 作用域鏈取決於函數被宣告時的位置,解析標識符的時候就先找目前作用域,再向外查找,直到全局,這樣一個順序;和函數在哪裡調用無關;

  3. 執行環境就是函數可訪問的資料和變數的集合,也就是函數的作用域鏈上的所有資料和變數;

  4. 執行環境堆疊就是根據程式碼執行順序,各執行環境按照堆疊的形式逐層訪問,並且用完了退出來扔掉;如果當前執行環境(存放目前作用域鏈裡的資料和變數)找不到變量,那就是找不到了,不會往之前的那個執行環境查找,它和作用域鍊是不同的;

作用域

  JavaScript沒有區塊級作用域的概念,只有函數級作用域:變數在宣告它們的函數體及其子函數內是可見的。

  作用域就是變數和函數的可存取範圍,控制變數和函數的可見性與生命週期,在JavaScript中變數的作用域有全域作用域和局部作用域。

  • 變數沒有在函數內宣告或宣告的時候沒有帶var就是全域變量,擁有全域作用域;

        <script type="text/javascript">
            function test1(){
                a = 1;//全局变量,只有在当前函数运行时,才有效            }
            test1();
            console.log(a);//1       注意test1函数必须运行,不然找不到a
        </script>
登入後複製
  • 全域變數可以當做window物件的屬性用,他們是一樣的;

        <script type="text/javascript">    
            var b = 1;//全局变量            
            console.log(b === window.b);
            //true  全局变量可以当做window对象的属性用,他们是一样的;
        </script>
登入後複製
  • window物件的所有屬性都有全域作用域,在程式碼任何地方都可以存取;

  • 函數內部聲明的變數就是局部變量,只能在函數體內使用,函數的參數雖然沒有使用var但仍然是局部變數。

        <script type="text/javascript">    
            var c = 1;//全局变量//            
            console.log(d);//ReferenceError: d is not defined    引用错误,当前作用域就是最外层作用域,依然找不到d
            function test2(d){
                console.log(c);
                //1   全局变量,哪都可以访问;(先找当前作用域,找不到,就向外层作用域找,直到window最外层,找到了)                console.log(d);//3   形参是局部变量,只有当前作用域下可以访问            }
            test2(3);        
            </script>
登入後複製

作用域鏈

  作用域鏈取決於函數被宣告時的位置,解析標識符的時候就先從目前作用域開始找,在當前當作用域中無法找到時,引擎就會在外層嵌套的作用域中繼續查找,直到找到該變量,或抵達最外層的作用域(也就是全域作用域)為止;它的路線已經被定死了,和函數在哪裡運行無關

        <script type="text/javascript">
            var a = 1;            
            var b = 2;            
            var c = 3;            
            var d = 4;            
            function inner(d) {//它的作用域链是inner---全局
                var c = 8;
                
                console.log(a);//1  当前作用域找不到a,去全局作用域找到了a=1                console.log(b);//2  当前作用域找不到b,去全局作用域找到了b=2                console.log(c);//8  当前作用域找到了c=8                console.log(d);//7  当前作用域找到了d=7,形参也是局部作用域
            //    console.log(e);//ReferenceError: e is not defined   引用错误,找不到e, 它的作用域链是inner---全局                console.log(a+b+c+d);//18            }            function outter(e) {                var a = 5;//inner()的作用域链是inner---全局,所以这个a相当于无效
                var b = 6;//inner()的作用域链是inner---全局,所以这个a相当于无效                inner(7);
            }
            outter(999);//这个999无效,里面的e根本找不到
        </script>
登入後複製
  • #在多層的嵌套作用域中可以定義同名的標識符,這叫作「遮蔽效應”,內部的標識符“遮蔽”了外部的標識符

  • 透過window.a這種技術可以存取那些被同名變數所遮蔽的全域變數。但非全域的變數如果被遮蔽了,無論如何都無法被存取;

        <script type="text/javascript">
            var a = &#39;Lily&#39;;            
            var b = &#39;Lucy&#39;;            
            function outer() {                
            var b = &#39;Jesica&#39;;                
            var c = &#39;Susan&#39;;                
            function inner(c) {
                console.log(a);//Lily                      
                console.log(window.b);//Lucy                    
                console.log(b);//Jesica                    
                console.log(c);//Jenifer                
                }
            inner(&#39;Jenifer&#39;);
          }
            outer();       
         </script>
登入後複製

執行環境

  執行環境(execution context),也叫執行上下文。每個執行環境都有一個變數物件(variable object),保存函數可存取的所有變數和資料(也就是函數的作用域鏈上的所有資料和變數)。我們的程式碼存取不到它,它是給引擎使用的;

  執行環境棧,當執行進入一個函數時,函數的執行環境就會被推入一個堆疊中。而在函數執行完之後,棧將其執行環境移除,它裡面的變數和資料會被標記清除,等待垃圾回收,再把控制權回傳給先前的執行環境。 javascript程式中的執行正是由這個機制控制著;

  需要注意的是如果當前執行環境(存放當前作用域鏈裡的資料和變數)找不到變量,那就是找不到了,不會往之前的那個執行環境查找,和作用域鍊是不一樣的

  程式碼的執行順序也不全是一行一行的執行,而是和函數的呼叫順序有關:

  • 程式碼進入全域執行環境,全域執行環境放入環境堆疊;

  • 當執行到一個函數時,就把這個函數的執行環境被推入到環境堆疊頂端,之前的執行環境往後;

  • #全域執行環境先進入,所以一直在底端;就跟堆疊的概念差不多;

  • 函數執行完之後,再把它的執行環境從作用域鏈頂端移除,它保存的資料和函數都被標記清除,等待垃圾回收;

  • 控制權交給先前的執行環境,繼續往下執行;

  • #當頁面關閉時,全域執行環境才會銷毀;

  • #程式碼執行進入全域執行環境,並對全域執行環境中的程式碼進入宣告提升;    

  • 執行第2行,賦值a=1; 然後第3行賦值b=2; 則第4行賦值c=3; 則第5行賦值d=4;

  • 執行第20行,呼叫outer(999)函數,然後進入outer(999)函數執行環境,宣告提升,並將實參999傳給形參e;現在環境堆疊中有兩個執行環境,outer(999)是目前執行環境;

  • 執行第16行,賦值a=5; 則第17行賦值b=6;    

  • #執行第18行,呼叫inner(7)函數,然後進入inner(7)函數執行環境,宣告提升,並將實參7傳給形參d;

  • 執行第7行,賦值c=8; 然後運算並輸出;

#程式碼最佳化

  由於在作用域鏈上尋找變數是需要消耗性能的,我們應該盡快的找到變量,所以在函數多層嵌套的時候,我們應盡可能的使用函數內部的局部變量;

  我們在函數內部使用全局變量可以說是一種跨作用域操作,如果某個跨作用域的值在函數的內部被多次使用,那麼我們就把它儲存到局部變數裡,這樣可以提高效能。

以上是javascript 作用域鏈與執行環境的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1662
14
CakePHP 教程
1418
52
Laravel 教程
1311
25
PHP教程
1261
29
C# 教程
1234
24
c語言中typedef struct的用法 c語言中typedef struct的用法 May 09, 2024 am 10:15 AM

typedef struct 在 C 語言中用於建立結構體類型別名,簡化結構體使用。它透過指定結構體別名將一個新的資料類型作為現有結構體的別名。優點包括增強可讀性、程式碼重複使用和類型檢查。注意:在使用別名前必須定義結構體,別名在程式中必須唯一且僅在其宣告的作用域內有效。

java中的variable expected怎麼解決 java中的variable expected怎麼解決 May 07, 2024 am 02:48 AM

Java 中的變數期望值異常可以透過以下方法解決:初始化變數;使用預設值;使用 null 值;使用檢查和賦值;了解局部變數的作用域。

js中閉包的優缺點 js中閉包的優缺點 May 10, 2024 am 04:39 AM

JavaScript 閉包的優點包括維持變數作用域、實作模組化程式碼、延遲執行和事件處理;缺點包括記憶體洩漏、增加了複雜性、效能開銷和作用域鏈影響。

c++中的include什麼意思 c++中的include什麼意思 May 09, 2024 am 01:45 AM

C++ 中的 #include 預處理器指令將外部來源檔案的內容插入到目前原始檔案中,以複製其內容到目前原始檔案的相應位置。主要用於包含頭文件,這些頭文件包含程式碼中所需的聲明,例如 #include <iostream> 是包含標準輸入/輸出函數。

C++ 智慧指標:全面剖析其生命週期 C++ 智慧指標:全面剖析其生命週期 May 09, 2024 am 11:06 AM

C++智慧指標的生命週期:建立:分配記憶體時建立智慧指標。所有權轉移:透過移動操作轉移所有權。釋放:智慧指標離開作用域或被明確釋放時釋放記憶體。物件銷毀:所指向物件被銷毀時,智慧型指標成為無效指標。

c++中函數的定義和呼叫可以巢狀嗎 c++中函數的定義和呼叫可以巢狀嗎 May 06, 2024 pm 06:36 PM

可以。 C++ 允許函數巢狀定義和呼叫。外部函數可定義內建函數,內部函數可在作用域內直接呼叫。巢狀函數增強了封裝性、可重複用性和作用域控制。但內部函數無法直接存取外部函數的局部變量,且傳回值類型需與外部函數宣告一致,內部函數不能自遞歸。

vue中let和var的區別 vue中let和var的區別 May 08, 2024 pm 04:21 PM

在 Vue 中,let 和 var 宣告變數時在作用域上存在差異:作用域:var 具有全域作用域,let 具有區塊級作用域。區塊級作用域:var 不會建立區塊級作用域,let 建立區塊級作用域。重新宣告:var 允許在同一作用域內重新宣告變數,let 不允許。

C++ 智慧指標:從基礎到高級 C++ 智慧指標:從基礎到高級 May 09, 2024 pm 09:27 PM

智慧指針是C++專用指針,能夠自動釋放堆記憶體對象,避免記憶體錯誤。類型包括:unique_ptr:獨佔所有權,指向單一物件。 shared_ptr:共享所有權,允許多個指標同時管理物件。 weak_ptr:弱引用,不增加引用計數,避免循環引用。使用方法:使用std命名空間的make_unique、make_shared和make_weak建立智慧指標。智慧型指標在作用域結束時自動釋放物件記憶體。進階用法:可以使用自訂刪除器控制物件釋放方式。智慧型指標可有效管理動態數組,防止記憶體洩漏。

See all articles