首頁  >  文章  >  web前端  >  javascript 作用域鏈與執行環境

javascript 作用域鏈與執行環境

迷茫
迷茫原創
2017-03-26 16:49:011157瀏覽

作用域、作用域鏈、執行環境、執行環境堆疊以及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