javascript要點總結
來自: http://my.oschina.net/u/2246410/blog/628611
javascript要點總結
介紹下javascript中的最重要幾個概念執行環境、作用域、以及原型鏈。理解了這兩個概念才能寫出好的javascript代碼,特別是在理解閉包、寫插件或者使用使用框架快速上手。
一、執行環境、作用域
1、執行環境(摘抄于javascript高級程序設計):
執行環境(execution context,為簡單起見,有時也稱為“環境”)是 JavaScript 中最為重要的一個概念。執行環境定義了變量或函數是否有權訪問的其他數據,決定了它們各自的行為。每個執行環境都有一個與之關聯的變量對象(variable object) ,環境中定義的所有變量和函數都保存在這個對象中。雖然我們編寫的代碼無法訪問這個對象,但解析器在處理數據時會在后臺使用它。
全局執行環境是最外圍的一個執行環境。根據 ECMAScript 實現所在的宿主環境不同,表示執行環境的對象也不一樣。在 Web 瀏覽器中,全局執行環境被認為是 window 對象(第 7 章將詳細討論) ,因此所有全局變量和函數都是作為 window 對象的屬性和方法創建的。某個執行環境中的所有代碼執行完畢后,該環境被銷毀,保存在其中的所有變量和函數定義也隨之銷毀(全局執行環境直到應用程序退出——例如關閉網頁或瀏覽器——時才會被銷毀) 。
每個函數都有自己的執行環境。當執行流進入一個函數時,函數的環境就會被推入一個環境棧中。而在函數執行之后,棧將其環境彈出,把控制權返回給之前的執行環境。ECMAScript 程序中的執行流正是由這個方便的機制控制著。
2、作用域(摘抄于javascript高級程序設計):
當代碼在一個環境中執行時,會創建變量對象的一個作用域鏈(scope chain) 。作用域鏈的用途,是保證對執行環境有權訪問的所有變量和函數的有序訪問。作用域鏈的前端,始終都是當前執行的代碼所在環境的變量對象。如果這個環境是函數,則將其活動對象(activation object)作為變量對象。活動對象在最開始時只包含一個變量,即 arguments 對象(這個對象在全局環境中是不存在的) 。作用域鏈中的下一個變量對象來自包含(外部)環境,而再下一個變量對象則來自下一個包含環境。這樣,一直延續到全局執行環境;全局執行環境的變量對象始終都是作用域鏈中的最后一個對象。
ps:在C中,每次執行一個函數,都會在內存的棧重新中劃定一個區域,加載實參、本地變量、返回地址等信息。這片新的內存棧就是執行環境,而執行鏈就是傳遞的指針(不是具體變量、而且每個函數都是傳遞指針)。所有本棧幀可以范圍自己的變量和前面棧幀的變量,直到全局變量(window對象)。而前面的棧幀不能訪問后面的棧幀變量。
3、案例:
<!DOCTYPE html> <html> <head> <script> var one="One"; function firstFunction(){ var two="Two"; console.log("Two:--"+one); console.log("Two:--"+two); //console.log("Two:--"+three); function sencondeFunction(){ var three="three"; console.log("three:--"+one); console.log("three:--"+two); console.log("three:--"+three); } sencondeFunction(); } firstFunction(); </script> </head> </html>
正常
把注釋部分打開(前一個棧幀、訪問后一個棧幀。會出現錯誤)
二、原型鏈
摘抄于《javascript高級程序設計》的概念:ECMAScript 中描述了原型鏈的概念,并將原型鏈作為實現繼承的主要方法。其基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。簡單回顧一下構造函數、原型和實例的關系:每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。那么,假如我們讓原型對象等于另一個類型的實例,結果會怎么樣呢?顯然,此時的原型對象將包含一個指向另一個原型的指針,相應地,另一個原型中也包含著一個指向另一個構造函數的指針。假如另一個原型又是另一個類型的實例,那么上述關系依然成立,如此層層遞進,就構成了實例與原型的鏈條。這就是所謂原型鏈的基本概念
1、首先一張圖:(摘抄于知乎)
2、開始瞎掰
a、我們的測試代碼
<!DOCTYPE html> <html> <head> <script> function firstFunction(){ this.two="two"; this.age="age"; } firstFunction.prototype.a="a"; var first=new firstFunction(); console.log(first); console.log(firstFunction.prototype); </script> </head> </html>
b、瀏覽器告訴我們真像
聯系上面的代碼,我們先畫一張圖
__proto__:屬性可以看作是原型鏈。
constructor:看作是java的字節碼文件,只是用戶定義的class對象,還沒有在內存中實現。
prototype:則是class在堆中的實現,才具有使用價值。
接著將firstFunction.prototype中的constructor繼續展開(后面的主語):
從這個圖我們看見,prototype原型的__proto__是Object對象。然后,constructor的__proto__是function()對象,然后我們繼續作畫:
在圖上添加2條紅線后,我們還需要展開 __ptoto__:function(),如下圖
從這我們發現function的__proto__也是Object,再把我們的畫補齊:
后面的__proto__就展開也沒有__proto__、constructor、prototype了,就不上圖了。這里我們發現這圖還有些變扭。根據《javascript高級程序設計》中描述:有prototype必然有對應的constructor,有constructor比然有對應的prototype。補全
所有的function的__proto__都是function.prototype。而所有prototype的__proto__都是object.prototype。最后object.prototype的__proto__指向的null