JS 執行環境、做用域鏈、活動對象

JS執行環境

執行環境(Execution context,EC)或執行上下文,是JS中一個極爲重要的概念javascript

執行環境分爲三種(全局執行環境,函數執行環境,evel()執行環境)前端

js爲每個執行環境關聯了一個變量對象。環境中定義的全部變量和函數都保存在這個對象中

EC的組成

當JavaScript代碼執行的時候,會進入不一樣的執行環境(執行上下文),這些執行環境會構成了一個執行環境棧(執行上下文棧)(Execution context stack,ECS)。見下圖:
圖片描述java

變量對象

變量對象(VO):變量對象即包含變量的對象,除了咱們沒法訪問它外,和普通對象沒什麼區別。變量對象存儲了在上下文中定義的變量和函數聲明

變量對象和活動對象(AO)

  1. 活動對象和變量對象實際上是一個東西,只是變量對象是規範上的或者說是引擎實現上的,不可在 JavaScript 環境中訪問,只有到當進入一個執行上下文中,這個執行上下文的變量對象纔會被激活,因此才叫 activation object

,而只有被激活的變量對象,也就是活動對象上的各類屬性才能被訪問。函數

  1. 活動對象是在進入函數執行環境時刻被建立的,它經過函數的 arguments 屬性初始化。arguments 屬性值是 Arguments 對象。

變量對象和活動對象的關係

未進入執行階段以前,變量對象(VO)中的屬性都不能訪問!可是進入執行階段以後,變量對象(VO)轉變爲了活動對象(AO),裏面的屬性都能被訪問了,而後開始進行執行階段的操做。

它們其實都是同一個對象,只是處於執行環境的不一樣生命週期。this

AO 其實是包含了 VO 的。由於除了 VO 以外,AO 還包含函數的 parameters,以及 arguments 這個特殊對象。也就是說 AO 的確是在進入到執行階段的時候被激活,可是激活的除了 VO 以外,還包括函數執行時傳入的參數和 arguments 這個特殊對象。

   AO = VO + function parameters + argumentsspa

執行環境分析

全局執行環境是最外圍的執行環境,全局執行環境被認爲是window對象,所以全部的全局變量和函數都做爲window對象的屬性和方法建立的。
js的執行順序是根據函數的調用來決定的,當一個函數被調用時,該函數環境的變量對象就被壓入一個環境棧中。而在函數執行以後,棧將該函數的變量對象彈出,把控制權交給以前的執行環境變量對象。

eg:3d

var scope = "global"; 
      function fn1(){
         return scope; 
      }
      function fn2(){
         return scope;
      }
      fn1();
      fn2();

演示以下:code

圖片描述

[[Scope]] 做用域

變量的做用域

變量的做用域就兩種:全局變量和局部變量對象

全局做用域:最外層函數定義的變量擁有全局做用域,即對任何內部函數來講,都是能夠訪問的:eg:
var outerVar = "outer";
          function fn(){
              console.log(outerVar);
      }
          fn();//result:outer
局部做用域:局部做用域通常只在固定的代碼片斷內可訪問到,而對於函數外部是沒法訪問的
function fn(){
         var innerVar = "inner";
      }
      fn();
      console.log(innerVar);// ReferenceError: innerVar is not defined
注意:函數內部聲明變量的時候,必定要使用var命令。若是不用的話,你實際上聲明瞭一個全局變量!
function fn(){
            age = 18;
        }
        fn();
        console.log(age);// 18

再來看一個有趣的現象:blog

var scope = "global";
      function fn(){
         console.log(scope);//result:undefined
         var scope = "local";
         console.log(scope);//result:local;
      }
      fn();

分析:第一個輸出竟然是undefined,本來覺得它會訪問外部的全局變量(scope=」global」),可是並無。這能夠算是javascript的一個特色,只要函數內定義了一個局部變量,函數在解析的時候都會將這個變量「提早聲明」,他就等價於下面的代碼:

var scope = "global";
      function fn(){
         var scope;//提早聲明瞭局部變量
         console.log(scope);//result:undefined
         scope = "local";
         console.log(scope);//result:local;
      }
      fn();

[[Scopr Chain]] 做用域鏈

理解:根據在內部函數能夠訪問外部函數變量的這種機制,用鏈式查找決定哪些數據能被內部函數訪問,這就是做用域鏈

上面給出了環境變量。下面仔細分析下做用域鏈

當某個函數第一次被調用時,就會建立一個執行環境(execution context)以及相應的做用域鏈,並把做用域鏈賦值給一個特殊的內部屬性([scope])。而後使用this,arguments(arguments在全局環境中不存在)和其餘命名參數的值來初始化函數的活動對象(activation object)。當前執行環境的變量對象始終在做用域鏈的第0位。以上述執行環境分析的小例子爲例進行圖解:當第一次調用fn1時。

圖片描述

解析:能夠看到fn1活動對象裏並無scope變量,因而沿着做用域鏈(scope chain)向後尋找,結果在全局變量對象裏找到了scope,因此就返回全局變量對象裏的scope值。

再分析下面的代碼:

function outer(){
         var scope = "outer";
         function inner(){
            return scope;
         }
         return inner;
      }
      var fn = outer();
      fn();

圖片描述

總結

說實話,這節真的是很難,如今仍是似懂非懂,不知道在學前端的小夥伴大家以爲呢?若是大家以爲這節學會了,能夠給我留言,我是真心不懂這節的內容,但願有會的小夥伴能夠給我點幫助!謝謝!

相關文章
相關標籤/搜索