一、執行環境及做用域 javascript
(1).執行環境:java
定義了變量或函數有權訪問的其它數據,決定了它們的各自行爲。每一個執行環境都有一個與之關聯的變量對象(variable object, VO),執行環境中定義的全部變量和函數都會保存在這個對象中,解析器在處理數據的時候就會訪問這個內部對象。web
全局執行環境是最外層的一個執行環境,在web瀏覽器中全局執行環境是window對象,所以全部全局變量和函數都是做爲window對象的屬性和方法建立的。每一個函數都有本身的執行環境,當執行流進入一個函數的時候,函數的環境會被推入一個函數棧中,而在函數執行完畢後執行環境出棧並被銷燬,保存在其中的全部變量和函數定義隨之銷燬,控制權返回到以前的執行環境中,全局的執行環境在應用程序退出(瀏覽器關閉)纔會被銷燬。編程
(2).做用域:數組
做用域就是變量和函數的可訪問範圍,控制着變量和函數的可見性與生命週期,在JavaScript中變量的做用域有全局做用域和局部做用域。瀏覽器
全局做用域:任何地方均可以定義擁有全局做用域的變量。緩存
a.沒有用var聲明的變量(除去函數的參數)都具備全局做用域,成爲全局 變量,因此聲明局部變量必需要用var。安全
b.window的全部屬性都具備全局做用域閉包
c.最外層函數體外聲明的變量也具備全局做用域 app
局部做用域:局部變量的優先級高於全局變量。
a.函數體內用var聲明的變量具備局部做用域,成爲局部變量
b.函數的參數也具備局部做用域
JavaScript是函數做用域(function scope),沒有塊級做用域。不管函數體內的變量在什麼地方聲明,對整個函數都是可見的,即JavaScript函數裏聲明的全部變量都被提早到函數體的頂部,只是提早變量聲明,變量的賦值仍是保留在原位置
(3).做用域鏈:
JavaScript的變量都是對象的屬性,而該對象可能又是其它對象的屬性,而全部的對象都是全局對象的屬性,因此這些對象的關係能夠看做是一條鏈,因爲每一個對象都有一個做用域,因此造成了一個做用域鏈。鏈頭就是變量所處的對象,鏈尾就是全局對象。
當代碼在一個環境中執行時,會建立變量對象的一個做用域鏈來保證對執行環境有權訪問的變量和函數的有序訪問。
二、原型鏈、繼承
(1)理解原型對象
1).只要建立了一個新函數,就會爲該函數建立一個prototype屬性,這個屬性指向函數的原型對象;
2).全部原型對象都會自動得到一個constructor(構造函數)屬性,這個屬性包含一個指向prototype屬性所在函數的指針;
3).當調用構造函數建立一個新實例後,該實例的內部將包含一個指針(內部屬性),指向構造函數的原型對象。
(2)原型鏈
綜上所述,假如咱們讓原型對象等於另外一個類型的實例,則此時的原型對象將包含一個指向另外一個原型的實例,相應地,另外一個原型中也包含着一個指向另外一個構造函數的指針。假如另外一個原型又是另外一個類型的實例,那麼上述關係依然成立,如此層層遞進,就構成了實例與原型的鏈條,這就是原型鏈。
【注】:全部引用類型默認都繼承了Object,而這個繼承也是經過原型鏈實現的。全部函數的默認原型都是Object的實例,所以默認原型都會包含一個內部指針,指向Object.prototype。這也正是全部自定義類型都會繼承toString(),valueOf()等默認方法的根本緣由。
(3)繼承
1).經過原型鏈實現。不能使用對象字面量建立原型方法,由於這樣會重寫原型鏈。
缺點:最主要的問題是包含引用類型值的原型;二是在建立子類型的實例時,不能向超類型的構造函數中傳遞參數。
2)借用構造函數。在子類型構造函數的內部調用超類型構造函數。使用apply()和call()方法,能夠向超類型的構造函數中傳遞參數。apply()和call()的做用同樣,只是專遞的參數形式不一樣,apply()的參數是以數組的形式傳遞,call()中是展開的形式。
缺點:函數複用無從談起,並且在超類型的原型中定義的方法,對子類型而言是不可見的。
3).組合繼承(原型鏈+借用構造函數)。避免了1)、2)的缺陷,融合了他們的優勢,成爲javascript最經常使用的繼承模式,並且,instanceof和isPrototypeOf()也可以用於識別基於組合繼承建立的對象。
三、閉包
(1).概念:有權訪問另外一個函數做用域中的變量的函數。簡單理解爲「定義在一個函數內部的函數」。
(2).好處:保護函數內的變量安全,增強了封裝性;在內存中維持一個變量(緩存);匿名自執行函數;模擬面向對象編程。
(3).應用場景:使用閉包代替全局變量;函數外或在其餘函數中訪問某一函數內部的參數;包裝相關功能;爲節點循環綁定click事件,在事件函數中使用當次循環的值或節點,而不是最後一次循環的值或節點;
(4).缺點:常駐內存,會增大內存使用量,使用不當很容易形成內存泄露,更重要的是,對閉包的使用不當會形成無效內存的產生。