關於JavaScript的執行域,標識符解析,閉包的研究

· 作者:laruence(http://www.laruence.com/)
· 本文地址: http://www.laruence.com/2008/07/28/210.html
· 轉載請註明出處

  在js中,作用域的概念和其他語言差不多, 在每次調用一個函數的時候 ,就會進入一個函數內的作用域,當從函數返回以後,就返回調用前的作用域,但js的實現方式卻和一般語言不同,並非用“堆棧”方式,而是使用列表,具體過程如下(ECMA262中所述):
   在一個函數對象被創建的時候, 會創建一個活動對象(也就是一個對象),然後對於每一個函數的形參,都命名爲該活動對象的命名屬性:
var func = function(lps, rps){
             ........
}
     對於上面的列子,會創建一個活動對象(假設爲aObj),給這個對象添加倆個命名屬性aObj.lps, aObj.rps; 然後還會創建一個arguments對象,這個對象以數組的方式保存調用參數,還有callee等其他參數;然後將arguments也作爲活動對象(假設爲aObj)的一個同名命名屬性(arguments);還有就是,對於每一個這個函數申明,或者定義的變量,都作爲該活動對象的同名命名屬性。內部函數也是一樣。
 
    在真正的調用時刻,會做一個叫做變量實例化的過程,也就是將調用參數賦值給形參數,對於缺少的調用參數,賦值爲undefined。

    接下來,談談作用域, 在js中,作用域的實現,是通過一個列表[[scope]]。對於每一個js的函數對象,都維護一個內部的對象列表[[scope]],這個列表由上面提到的一個個活動對象組成。
   
    當調用一個函數的時候,這個函數的活動對象列表,將保存該函數作用域(調用者的作用域)列表,然後將對於這個被調用函數所生成的活動對象,置於[[scope]]的最前端。

    當發生標識符解析的時候, 會逆向查詢這個[[scope]]列表的每一個活動對象的屬性,如果找到同名的就返回。找不到,那就是這個標識符沒有被定義。

  
function a(){
  ....
}

function b(){
 a();
}
對於上面的列子,當調用b()的時候, b的[[scope]]由: 全局活動對象->b的活動對象組成。
而當b()在內部調用a()的時候,a()的[[scope]]由:全局活動對象->b的活動對象->a的活動對象組成。

這樣,就構成了js自己的作用域的機制。。


接下來談談閉包,ECMA262沒有規定垃圾回收機制的具體實現,但一般來說,垃圾回收機制的原理都是,如果一個對象沒有再
被引用,那麼這個對象就會成爲垃圾回收的目標。

接下來結合前面講的,分析如下代碼:
 
function a(){

  return funtion  b(){
   .....};;
}

var ref = a();

當調用a()的時候,a返回了一個叫做b的函數對象的引用。 當從a調用返回以後,因爲ref引用了b(),所以在b()的[[scope]]上的,已經被變量實例化了的a的活動對象就不會被垃圾回收,那麼這樣,當在外部直接調用ref所引用的b時,就可以訪問到b()函數外層的a()函數對象已經被實例化了的各個參數。

這樣就形成了一個閉包。也可以理解爲一個不會被回收的函數對象列表,不過要注意的時候,在這個列表中的a()的活動對象是已經被實例化了的。

現在根據前面所講的這些,討論一個問題,就是對於js對象編程中所實現的"私有成員":
 
function class(){
  var private;
  this.public;
}
做過Javascript面對對象編程的朋友一定知道,對於上面的代碼,private變量是一個私有的變量,而public變量是共有的,那麼他們具體是怎麼實現的呢?

結合上面的討論,我們來分析一下,
 對於private, 它會被作爲class函數對象的活動對象的一個屬性,那麼當class函數對象(構造函數)執行結束以後,該活動對像就會被回收,那麼自然,這個private也就不能再被外部訪問了,也就是模擬了私有變量。
 而對於this.public,我們知道this在js中是一個關鍵字,而不是一個標識符,它指向調用者的引用, 比如:
var objRef = new Class();
這個時候,this指向的是 objRef,所以,,,,,,很顯然,這個時候public就可以通過objRef來訪問了,公有的屬性了。。。

當然,你也許會發現,如果是這樣的話,每次new一個對象的時候,這種形式的共有對象,每次都會new一個新的對象,會很浪費資源,所以,最好還是通過函數對象的原型來創建公有的屬性。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章