不管是with表達式仍是try-catch表達式的catch子句,以及包含()的函數,都被認爲是動態做用域。一個動態做用域只由於代碼運行而存在。所以沒法經過靜態分析(查看代碼機構)來肯定(是否存在做用域)。例如:編程
function execute(code) {
(code);
function subroutine(){
return window;
}
var w = subroutine();
//what value is w?
};
execute()函數看上去像一個動態做用域,由於它使用了()。w變量的值與code有關。大多數狀況下,w將等價於全局變量window對象,可是請考慮以下狀況:數組
execute("var window = {};")
這種狀況下,()在execute()函數中建立了一個局部的window變量,因此這個w將等價於這個局部的window變量而不是全局的那個。因此說,不運行這段代碼是沒有辦法瞭解具體狀況的,標識符window的確切含義不能預先肯定。瀏覽器
閉包是JavaScript最強大的一個方面,它容許函數訪問局部範圍以外的數據。閉包的使用在當今最複雜的網頁應用中無處不在,不過,有一種性能影響與閉包有關。緩存
爲了解閉包的有關性能問題,考慮下面的例子:閉包
function assignEvents(){
var id = "xdi9592";
document.getElementById("save-btn").onclick = function(event){
saveDocument(id);
};
}
assignEvents()函數爲一個dom元素制定了一個事件處理句柄,此事件處理句柄是一個閉包,當assignEvents()執行時建立,能夠訪問其範圍內部的id變量,用這種方法封閉對id變量的訪問,必須建立一個特定的做用域鏈。dom
當assignEvents()被執行時,一個激活對象被建立,幷包含了一些應有的內容,其中包括id變量。它將成爲運行期上下文做用域鏈上的第一個對象,全局對象是第二個。當閉包建立時,[[Scope]]屬性與這些對象一塊兒被初始化。函數
因爲閉包的[[Scope]]屬性包含與運行期上下文做用域鏈相同的對象引用,會產生反作用。一般,一個函數的激活對象與運行期上下文一同銷燬。當涉及閉包時,激活對象就沒法銷燬了,由於引用任然存在於閉包的[[Scope]]屬性中,這意味着腳本中的閉包與非閉包函數相比,須要更多的內存開銷。在大型網頁應用中,這多是個問題,尤爲在IE中更被關注。IE使用非本地JavaScript對象實現DOM對象,閉包可能致使內存泄露。性能
當閉包被執行時,一個運行期上下文將被建立,它的做用域鏈與[[Scope]]中引用的兩個相同的做用域同時被初始化,而後一個新的激活對象爲閉包自身被建立。this
主要閉包中使用的兩個標識符,id和saveDocument,存在於做用域鏈第一個對象以後的位置上。這是閉包最主要的性能關注點:你常常訪問一些範圍以外的標識符每次訪問都致使一些性能損失。spa
在腳本中最好是當心地使用閉包,內存和運行速度都值得被關注。將經常使用的域外變量存入局部變量中,而後直接訪問局部變量。
大多數JavaScript代碼以面向對象的形式編寫。不管經過建立自定義對象仍是使用內置對象,諸如文檔對象模型(DOM)和瀏覽器對象模型(BOM)之中的對象。所以,存在不少對象成員訪問。
對象成員包括屬性和方法,在JavaScript中,兩者差異甚微。對象的一個命名成員能夠包括任何數據類型。既然函數也是一種對象,那麼對象成員除了傳統的數據類型外,也能夠包含一個函數。當一個成員用了一個函數時,它被稱做一個「方法」,而一個非函數類型的數據則被稱做「屬性」。
對象成員比直接量或局部變量訪問速度慢,在某些瀏覽器上比訪問數組項還要慢。這和JavaScript中對象的性質有關。
JavaScript中的對象是基於原形的,原形是其餘對象的基礎,定義並實現了一個新對象所必須具備的成員。這一律念徹底不一樣於傳統面向對象編程中「類」的概念,它定義了建立新對象的進程。原形對象爲給定類型的對象實例所共享,所以全部實例共享原型對象的成員。
一個對象經過一個內部屬性綁定到它的原形。Firefox ,Safari和Chrome向開發人員開放這一屬性,稱做__proto__,其餘瀏覽器貌似不容許腳本訪問這一屬性。任什麼時候候你建立一個內置類型的實例,如object或者Arrary,這些實例自動擁有一個Object做爲他們的原形。
所以,對象能夠有兩種類型的成員:實例成員(「own」成員)和原造成員。實例成員直接存在於實例自身,而原造成員則從對象原形繼承。如:
var book = { title: "High Performance JavaScript", publisher: "Yahoo! Press" }; alert(book.toString()); //"[object Object]"
如 book對象有兩個實例成員:title 和publisher,注意它並無定義tostring()接口,可是這個接口卻被調用了,也沒用拋出錯誤。toString()函數就是一個book對象繼承的原造成員。
對象的原形決定了一個實例的類型。默認狀況下,全部對象都是Object 的實例,並繼承了全部基本方法。如toString()。也能夠用「構造器」建立另一種類型的原形。
function Book(title, publisher){ this.title = title; this.publisher = publisher; } Book.prototype.sayTitle = function(){ alert(this.title); }; var book1 = new Book("High Performance JavaScript", "Yahoo! Press"); var book2 = new Book("JavaScript: The Good Parts", "Yahoo! Press"); alert(book1 instanceof Book); //true alert(book1 instanceof Object); //true book1.sayTitle(); //"High Performance JavaScript" alert(book1. toString()); //"[object Object]"
Book構造器用於建立一個新的Book實例。book1的原形(__proto__)是Book.prototype,Book.prototype的原形是Object。這就建立了一個原形鏈,book1和book2繼承了他們的成員。
主要的是,兩個Book實例共享同一個原形鏈。每一個實例擁有本身的title和publisher屬性,可是其餘成員均繼承自原形。當book1.toString()被調用時,搜索工做必須深刻原形鏈才能找到對象成員"toString",深刻原形鏈越深,搜索速度就越慢。每深刻原形鏈一層都會增長性能損失。搜索實例成員的過程比訪問直接量或者局部量負擔更重,因此增長遍歷原形鏈的開銷正好放大了這種效果。
因爲對象成員可能包含其餘成員,例如不太常見的寫法window.location.href這種模式。每遇到一個點號,JavaScript引擎就要在對象成員上執行一次解析過程。成員嵌套越深,訪問速度越慢。location.href老是快於window.location.href,然後者也要比window.location.href.toString()更快。若是這些屬性不是對象的實例屬性,那麼成員解析還要在每一個點上索搜原形鏈,這將須要更長時間。
因爲全部這些性能問題與對象成員有關,因此若是可能的話就避免使用他們。更確切的說,只有在必要狀況下使用對象成員。例如沒有理由在一個函數中屢次讀取同一個對象成員的值:
function hasEitherClass(element, className1, className2){ return element.className == className1 || element.className == className2; }
element.className被訪問了兩次,咱們能夠存入一個局部變量,消除一次搜索過程:
function hasEitherClass(element, className1, className2){ var currentClassName = element.className; return currentClassName == className1 || currentClassName == className2; }
通常來講,若是在同一函數中你要屢次讀取同一個對象屬性,最好將它存入到一個局部變量。以局部變量替代屬性,避免多餘的屬性查找帶來的性能開銷。在處理嵌套對象成員時這點特別重要,他們會對運行速度產生難以置信的影響。
1.在JavaScript中,數據存存儲的位置能夠對代碼總體性能產生重要影響。有4種數據類訪問類型:直接變量,變量,數組項,對象成員。他們有不一樣的性能考慮。
2.直接變量和局部變量訪問速度很是快,數組項和對象成員須要更長時間。
3.局部變量比域變量快,由於它位於做用域鏈的第一個對象中。變量在做用域鏈中的位置越深訪問所需的時間就越長。全局變量老是最慢的,由於它們老是位於做用域鏈的最後一環。
4.避免使用with表達式,由於它改變了運行期上下文的做用域鏈。並且應當當心對待try-catch表達式catch子句,由於它具備一樣的效應。
5.嵌套對象成員會形成重大性能影響,儘可能少用。
6.一個屬性或方法在原形鏈中的位置越深,訪問速度就越慢。