JavaScript的做用域與做用域鏈||閉包以及爲何要使用閉包||對this的理解

一、JS高級程序設計關於這些個問題的解釋:

一、執行環境及做用域:

執行環境(execution context,也有稱之爲執行上下文)是JS語言中最重要的一個概念。javascript

Javascript沒有代碼塊做用域的概念,局部做用域是針對函數來講的。前端

執行環境定義了變量或者函數有權訪問到的其餘數據,決定了他們的各自行爲。java

每一個執行環境都有一個與之關聯的變量對象(variable object),執行環境中定義的全部變量和函數都保存在這個對象中。沒法訪問,可是解析器在後臺執行中要用到。jquery

全局執行環境是最外圍的執行環境。根據ECMAScript實現的宿主不一樣,表示執行環境的對象也不同。Web瀏覽器中,全局執行環境是window對象,所以全局函數和全局變量都是做爲window的對象和方法。瀏覽器

某個執行環境中的全部代碼執行完畢後將被銷燬,全局執行環境在關閉網頁的時候纔會被銷燬。閉包

每一個函數都有本身的執行環境。當執行流進入函數的時候,函數的環境被推入到一個環境棧中。在函數執行之後,棧將其環境彈出,把控制權交給以前的執行環境。框架

當代碼在一個環境中執行時,會建立變量對象的一個做用域鏈(scope chain)函數

做用域鏈的做用是:是保證對執行環境有權訪問的全部變量和函數的有序訪問。做用域的前端始終是當前執行的代碼所在的環境變量的變量對象。若是這個環境是一個函數,則將其活動對象(activation object)做爲變量對象。做用域鏈中的下一個變量對象來自於包含環境。全局執行環境始終是做用域鏈中最後一個對象。ui

標識符解析始終是沿着做用域鏈一級一級地搜索標識符的過程,前端開始,逐級向上,直到找到標識符爲止,找不到就會報錯。this

函數的做用域鏈包含着兩個對象:它本身的變量對象(其中定義了arguments),和全局環境的變量對象。 

js做用域分函數做用域和全局做用域。

當代碼在一個環境中執行時,會建立變量對象的一個做用域鏈(scope chain)。

做用域鏈的做用是:是保證對執行環境有權訪問的全部變量和函數的有序訪問。做用域的前端始終是當前執行的代碼所在的環境變量的變量對象。若是這個環境是一個函數,則將其活動對象(activation object)做爲變量對象。做用域鏈中的下一個變量對象來自於包含環境。全局執行環境始終是做用域鏈中最後一個對象。

標識符解析始終是沿着做用域鏈一級一級地搜索標識符的過程,前端開始,逐級向上,直到找到標識符爲止,找不到就會報錯。

函數的做用域鏈包含着兩個對象:它本身的變量對象(其中定義了arguments),和全局環境的變量對象。

二、延長做用域鏈:

雖然js中的執行環境總共就兩種:全局和函數(局部),可是仍是有其餘的辦法來延長做用域鏈。就是在做用域的前端添加一個臨時增長的變量對象。

具體使用:try...catch語句塊的catch塊;和with語句。

對於with語句來講,會將指定的對象添加到做用域鏈中。

function buildUrl(){
      var qs = "?debug=ture";
      with(location){
            var url = href + qs;
      }
      return url; 
}

三、沒有塊級做用域:

js中沒有塊級做用域,只有全局做用域和函數做用域。注意在if語句||for語句中定義的變量會被添加到全局變量中。

可使用自執行語句來模擬塊級做用域。

使用var聲明的變量會被添加到最接近的環境中,函數內部就是函數做用域。若是初始化沒有使用var,就會被添加到全局做用域中。

四、查詢標識符:

 沿着做用域鏈向上查找。 

閉包以及爲何要使用閉包:

閉包與匿名函數不要搞混。

閉包:就是指有權訪問另外一個函數做用域中的變量的函數。建立閉包最多見的方式,就是在一個函數做用域內建立另外一個函數。而且返回另外一個函數。

須要閉包的緣由:當使用函數被調用時,會建立一個執行環境(上下文環境)以及相應的做用域鏈,使用arguments和其餘命名參數的值來初始化函數的活動對象(activation object)。函數執行過程就須要在做用域鏈中查找變量,查找過程不能向下,因此就須要閉包來讀取函數內部的變量。閉包會讓外層函數的變量一直存在於內存中。直到都不調用爲止。

外層函數的變量對象(活動對象)存在於內層函數的做用域鏈中。

閉包的問題:

一、過分使用閉包會形成內存佔用過多。

二、做用域鏈的這種配置引出一個問題,就是閉包只能取得包含函數中任何變量的最後一個值,閉包保存的是整個變量對象,而不是某個特殊的變量。

 

這裏打印的0~9是console.log打印的。最終保存的結果i都是10。

以上函數,在for循環中使用閉包,這樣最後讀取到的i是最後一個值。存在風險。改用以下的方式,將當前值保存下來,用一個自執行的閉包函數來保存變量,以後結果傳出。

js權威指南解釋做爲補充:

函數的執行依賴於變量做用域,這個做用域在函數定義的時候決定的,不是在函數調用的時候決定的。

古老解釋對於閉包:函數對象經過做用域鏈來相互關聯,函數體內的變量均可以保存在函數做用域內。

閉包能夠捕捉到局部變量(和參數),並一直保存下來。

閉包的應用場景以及優缺點:

應用場景:一、閉包的典型框架應該就是jquery了。

     二、閉包是javascript語言的一大特色,主要應用閉包場合主要是爲了:設計私有的方法和變量(模塊設計,自執行閉包)。

     三、這在作框架的時候體現更明顯,有些方法和屬性只是運算邏輯過程當中的使用的,不想讓外部修改這些屬性,所以就能夠設計一個閉包來只提供方法獲取。

優勢:1. 邏輯連續,當閉包做爲另外一個函數調用的參數時,避免你脫離當前邏輯而單獨編寫額外邏輯。

   2. 方便調用上下文的局部變量

         3. 增強封裝性,第2點的延伸,能夠達到對變量的保護做用。

缺點:閉包有一個很是嚴重的問題,那就是內存浪費問題,這個內存浪費不只僅由於它常駐內存,更重要的是,對閉包的使用不當會形成無效內存的產生。

關於閉包,就我本身的習慣而言,能不用就不用,若是非用不可,那就想辦法保持閉包對象的數量不多甚至惟一。

關於this:

this對象在運行時是基於函數的執行環境綁定的:在全局函數中,this等於window,當函數被看成某個對象的方法調用的時候,this等於那個對象,非對象的函數調用,this都會指向window。也就至關於說,誰調用這個函數,this就指向誰。

匿名函數的執行環境具備全局性。這時候this對象指向window。

每當建立一個函數的時候,函數在被調用的時候自動獲取兩個特殊的變量,this和arguments。

相關文章
相關標籤/搜索