javascript筆記:通過對範圍鏈和執行環境的深入理解所得出的提高javascript代碼效能的建議

來源:互聯網
上載者:User

  上篇文章裡我結束了對象的建立的內容,最後引出了範圍鏈和執行環境的問題。當我對這塊知識有了更深入的瞭解後,回頭看看jQuery源碼才知道大師們寫的代碼是如何的厲害,jQuery源碼裡很好的運用了範圍鏈和執行環境的知識來提升程式效能。

  好了,不廢話了,上篇博文裡對範圍講的比較簡略。其實對範圍的理解是理解整個javascript語言的關鍵所在,特別我在寫javascript筆記時候曾對很多怪異的javascript用法無法理解的透徹,究其原因還是沒有真正理解javascript裡範圍的概念。

  Javascript裡的範圍到底決定了什麼呢?範圍決定了那些變數能被函數所訪問(注意:範圍是函數的內部屬性,談到範圍是繞不開的function),範圍也確定了this指標的指向。上篇博文裡我說道,程式其實就是不斷檢索資料的過程,那麼檢索資料的效率決定了程式的效能,因此範圍既然決定那些變數能被訪問,當然也決定了檢索這些變數的方式,所以想寫出高效的javascript程式靈活運用範圍的原理是關鍵了。

  上篇博文裡面,我寫了一個函數,代碼如下:

<script type="text/javascript">
function add(a,b)
{
var sum = a + b;
return sum;
}
</script>

  大家可以看到這個函數屬於window而非function,在頁面被載入時候,add函數會被初始化,產生屬於自己的範圍鏈,上篇文章裡我在firebug裡設定斷點調試貼出了一個我下來的變數圖,認為這就是函數add的Scope所包含的變數,現在發現當時理解是錯誤的,那些變數是window的“全域環境”的變數圖而非是add函數的內部屬性Scope的變數圖。在此我糾正一下。

  下面我要著重講講範圍鏈和執行環境,這塊知識我在javascript對象建立的中篇裡提到過,這裡我將那些知識回顧下:

    什麼是執行環境呢?在javascript裡面執行環境分為兩類,一類是全域環境,一類是局部環境,整個頁面裡被共用的方法和屬性就是在全域環境,相對於全域環境,函數{}號裡的執行環境就是局部環境,執行環境定義了變數或函數有權訪問的其他資料,決定了它們各自的行為,每個執行環境都定義了一個與之相關的變數對象,環境中定義的所有變數和函數都儲存在這個對象裡,雖然我們自己編寫的代碼無法訪問這個對象,但解析器在處理資料時候後台會使用到它。
全域執行環境另一種說法是最外圍的一個執行環境,在web瀏覽器的範圍中(actionscript也是施行了ECMAScript標準,它的全域範圍就和javascript的全域範圍不同),全域執行環境被認為是window對象,因此全域變數和函數都是作為window對象的方法和屬性來建立的,全域執行環境知道應用程式退出比如關閉網頁或瀏覽器才會被銷毀。而局部環境則是以函數對象作為關聯對象。

  大家要注意環境的首碼是:執行,也就說只有函數被執行(局部執行環境)和頁面被載入(全域執行環境),下面就是頁面被載入時候的全域執行環境變數:

  現在我們要執行add函數了,代碼如下:

function add(a,b)
{
var sum = a + b;
return sum;
}

console.log(add(10,20));

  

  這是add函數的執行環境的變數圖是:

  1.firebug:

  2.chrome的代碼調試器:

  代碼的結構圖如下:

  在函數被執行時候,函數會建立一個“運行期上下文(execution context)”的內部對象,這個運行期上下文在我的理解裡就是函數的執行環境,每個運行期上下文都有自己的範圍鏈,用於標識符解析。

  當運行期上下文被建立時候,他的範圍鏈初始化為當前運行函數【Scope】屬性中所含的對象(見firebug和chrome調試器裡的記憶體配置圖,比如add函數除了a,b,sum,this還有arguments,不過這個在firebug和chrome調試器裡看不到的)。這些值按照它們出現在函數中的順序,被複製到執行期內容相關的範圍鏈中。這個過程一旦完成,一個被稱為“使用中的物件(activation object)”的新對象就為執行期上下文建立好了,使用中的物件作為函數運行期的可變對象,包含了所有局部變數,具名引數,參數集合以及this。然後此對象被推入到範圍鏈的前端。當運行期上下文被銷毀的時候,使用中的物件也隨之被銷毀。在函數執行過程中,每遇到一個變數都會進行一次標識符的解析,這種解析決定了我們從啥地方擷取變數或者將變數儲存到什麼地方,這個過程是搜尋整個函數運行期內容相關的範圍鏈,尋找同名的標識符,搜尋過程都是從範圍頭部開始,也就是當前運行函數的使用中的物件。找到了就使用它,沒有找到則會繼續搜尋範圍鏈中的下一個對象,搜尋過程會延續到找到標識符為止或者是沒有找到為止,這種情況就是標識符沒有被定義了

  在javascript裡使用變數就是在做標識符解析,由上面的解釋我們知道標識符的解析一定是有電腦效能的消耗的,當標識符位於執行內容範圍鏈的位置越深,效能也就越慢了,那麼到底什麼地方最慢了?比如我們舉例的函數add,當我們搜尋到global全域變數總會比函數內部的局部變數慢,假如我們定義個更複雜的函數裡面有多層嵌套的話,訪問全域變數就是效能的夢魘了。因此在函數中我們盡量多使用函數內部的局部變數。(由於瀏覽器的產品的差異,個別瀏覽器的訪問變數的效能可能會有差異,但是總體而言,訪問函數局部變數永遠是最快的)。

  盡量使用局部變數,就帶來一個十分重要的提高程式效能的用法:我們在函數內部使用全域變數可以說是一種跨範圍操作,如果某個跨範圍的值在函數的內部被使用到一次以上,那麼我們就把它儲存到局部變數裡

  代碼書寫的格式就是:

function ftn()
{
var doc = document;
.......
}

 

  將全域的變數用var定義到局部變數裡。

  這個用法在jQuery源碼裡一開頭就清晰可以到看:

var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context );
},

// Map over jQuery in case of overwrite
_jQuery = window.jQuery,

// Map over the $ in case of overwrite
_$ = window.$,

// Use the correct document accordingly with window argument (sandbox)
document = window.document,

  jQuery把經常使用的全域變數都儲存在函數的局部變數裡。

  

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.