[轉載]向進階Javascript程式員陣營邁進:Javascript一些概念研究總結

來源:互聯網
上載者:User

習慣於OOP語言編程後,會發現Javascript世界有很多匪夷所思的奇奇怪怪的現象(比如閉包),我花了大量的精力研究這些奇怪現象的根源,最後發現:源自於javascript的範圍不是塊級範圍,同時它有一套基於範圍鏈的標識尋找機制。本文大部分內容來自互連網,經過整理、改進而成。

  • Javascript引擎和DOM採用的記憶體回收演算法:引用計數
    javascript和DOM有各自的記憶體回收行程,單獨運作良好,合作時一不小心會出問題。引用計數這個演算法的缺陷就是:Javascript 對象和DOM對象彼此循環參考,造成彼此的引用計數永遠不能為0,記憶體回收行程無法正確回收這些參與循環參考的對象,最終造成記憶體流失(Memory Leak)。閉包是循環參考“大戶”。如果對記憶體回收感興趣,可以看看 垃圾收集趣史
  • 詞法範圍(lexical scope,一般簡稱範圍)、with/eval
    簡單來說javascript的範圍是由function劃分的。讀完這篇文章你會瞭解詞法範圍 Javascript運行機制淺探,with/eval這 兩個特例會擾亂範圍,即所謂動態範圍(dynamic scope)
  • 範圍鏈(Scope Chain) 和 標識尋找機制
    範圍鏈是一個鏈表(資料結構),它是Javascript的靈魂,只有理解了它才能理解Javascript世界奇奇怪怪的現象。範圍鏈由使用中的物件鏈成。
    標識尋找機制稍後結合函數執行的原理加以說明。
  • 使用中的物件(call object)
    國內很多人稱之為調用對象(call object),本文用英文call obejct(但我私下認為翻譯為"使用中的物件"更好,不至於和this所指的對象混淆。)
    非常特殊的javascript引擎內的對象,ECMAScript規範術語稱之為activation object(使用中的物件)。多個call object和全域對象組成範圍鏈(scope chain )
  • 函數的本質(有名函數、匿名函數)、函數的[[scope]]屬性   函數在javascript裡面是一個特殊的參考型別 ,它繼承於位於javascript世界最頂端的object,類型是Function,是其他常見參考型別的建構函式的所屬類型。
      在定義函數的時候,Javascript引擎會為function對象的一個私人[[scope]]屬性賦值,理論上只有js引擎自己才能訪問(也即:一般情況下無法通過文法來訪問,但Firefox下有一個__parent___可以訪問到)。匿名函數的[[scope]]屬性指向匿名函數定義時的內容物件;有名函數除了和匿名函數一樣,還會在[[scope]]屬性的頂端再指向一個Javascript對象(繼承自obejct.prototype),這個對象被連結到函數定義時的Scope Chain,他本身帶有一個屬性就是函數的名字,這確保函數內部的代碼可以無誤地訪問到自己的函數名以便進行遞迴。
      當定義函數的時候,javascript解析器會將函數的範圍鏈(scope chain)設定為定義函數時函數所在的“環境”,如果函數是一個全域函數,則scope chain中只有window對象。
      當執行函數時的微觀世界,請看稍後的說明。
  • 閉包(closure)
    javascript所有的函數都是閉包,但是只有嵌套形式的閉包(也是我們經常討論的形式)才能體現這個javascript 特性的強大。推薦閱讀這篇文章:
    深入理解JavaScript閉包(closure)
  • 函數執行時的範圍鏈和使用中的物件是如何形成的及與閉包的關係
    1、javascript解析器啟動時就會初始化建立一個全域對象global object,這個全域對象就 擁有了一些預定義的全域變數和全域方法,如Infinity, parseInt, Math,所有程式中定義的全域變數都是這個全域對象的屬性。在用戶端javascript中,Window就是這個javascript的全域對象。

    2、當javascript執行一個function時,會產生一個對象,稱之為call object,function中的局部變數和function的參數都成為這個call object的屬性,以免覆寫同名的全域變數。

    3、javascript解析器每次執行function時,都會為此function建立一個execution context執行環境,在此function執行環境中最重要的一點就是function的範圍鏈scope chain,這是一個對象鏈,由全域對象和使用中的物件構成,對象鏈具體構成過程見下面說明。

    4、標識的尋找機制:當javascript查詢變數x的值時,就會檢查此範圍鏈中第一個對象,可能是function的call object或全域對象(比如window),如果對象中有定義此x屬性,則傳回值,不然檢查範圍鏈中的下一個對象是否定義x屬性,在範圍鏈中沒有找到,最後返回undefined。

    5、當javascript執行一個function時,它會先將此function定義時的範圍作為其範圍鏈,然後建立一個使用中的物件(call object),置於範圍鏈的頂部,function的參數及內部var聲明的所有局部變數都會成為此調用對象的屬性。

    6、this關鍵詞指向方法的調用者,而不是以調用對象的屬性存在,同一個方法中的this在不同的function調用中,可能指向不同的對象。

    7、The Call Object as a Namespace。將使用中的物件當作命名空間使用,避免命名汙染。
    (function() {
    // 在方法體內用var聲明的所有局部變數,都是以方法調用時建立的活對象的屬性形式 存在。
    // 這樣就避免與全域變數發生命名衝突。
    })();

    8、javascript中所有的function都是一個閉包,但只有當一個嵌套函數被匯出到它所定義的範圍外時,這種閉包才強大。如果理解了閉包,就會理解function執行時的範圍鏈和使用中的物件,才能真正掌握javascript。

    9、嵌套閉包的微觀世界:在嵌套閉包時,當內建函式的引用被儲存到嵌套閉包之外一個全域變數或者一個對象的屬性時,在這種情況下,此內建函式有一個外部參考,並且在其外圍調用函數的使用中的物件中有一個屬性指向此內建函式。因為有其他對象引用此內建函式,所以在外圍函數被調用一次後,其建立的使用中的物件會繼續存在,並不會被記憶體回收行程回收(因為引用計數不為0),內建函式的參數和局部變數都會在這個使用中的物件中得以維持,javascript代碼任何形式都不能直接存取此使用中的物件,但是此使用中的物件是內建函式被調用時建立的範圍鏈的一部分,可以被內建函式訪問並修改。

最後介紹一個奇怪現象:下面的代碼,為什麼滑鼠移動到li上,title總是6,而不是我們所預想的數字呢?看你能不能根據以上的知識,解釋這種現象的原因。提示:變數尋找機制。

<html>
<head>
<title>迴圈內的閉包 應該謹慎</title>
</head>
<body>
<ul id="list">
<li>第1條記錄</li>
<li>第2條記錄</li>
<li>第3條記錄</li>
<li>第4條記錄</li>
<li>第5條記錄</li>
<li>第6條記錄</li>
</ul>
<script type="text/javascript">
var list_obj = document.getElementById("list").getElementsByTagName("li"); //擷取list下面的所有li的對象數組
for (var i = 0; i <= list_obj.length; i++) {
list_obj[i].onmousemove = function() {
this.style.backgroundColor = "#eee";
document.title=i
};
list_obj[i].onmouseout = function() {
this.style.backgroundColor = "#fff";
}
}
</script>
</body>
</html>複製代碼

為什麼上面的代碼改成下面的就好了呢?

<html>
<head>
<title>迴圈內的閉包 應該謹慎</title>
</head>
<body>
<ul id="list">
<li>第1條記錄</li>
<li>第2條記錄</li>
<li>第3條記錄</li>
<li>第4條記錄</li>
<li>第5條記錄</li>
<li>第6條記錄</li>
</ul>
<script type="text/javascript">
var list_obj = document.getElementById("list").getElementsByTagName("li"); //擷取list下面的所有li的對象數組
for (var i = 0; i <= list_obj.length; i++) {
(function(i){
list_obj[i].onmousemove = function() {
this.style.backgroundColor = "#eee";
document.title=i
};
list_obj[i].onmouseout = function() {
this.style.backgroundColor = "#fff";
}
})(i);
}
</script>
</body>
</html>複製代碼

 

 文章轉載自:http://www.cnblogs.com/kaima/archive/2009/03/07/advanced_javascript_concept.html

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.