閉包聽了不少次了,但是到底有那些具體的用法仍是不清楚,看了《JavaScript高級程序設計》,有點明白了。閉包
閉包其實就是一個函數,而這個函數有點特別,它可以訪問另外一個函數做用域中的變量,因此通常咱們看到的閉包存在形式都是在一個函數裏面。函數
示例:this
var iBaseNum = 10;//全局變量 function addNum(iNum1, iNum2) {//局部變量 function doAdd() {//閉包函數,有權訪問局部變量中的iNum1, iNum2參數以及全局變量iBaseNum return iNum1 + iNum2 + iBaseNum; } return doAdd(); }
咱們知道,當在函數內部定義了函數時,天然而然也就建立了閉包,閉包之因此強大,是由於它內部存在着一條做用域鏈。這條做用域包含着本身的做用域,包含函數的做用域和全局做用域。當代碼在一個環境中執行時,會建立變量對象的一個做用域鏈。做用域鏈的用途是保證對執行環境有權訪問的全部變量和函數的有序訪問。設計
一般,當一個函數執行完了,它的做用域以及其全部變量都回在函數執行結束後被銷燬。,可是當函數返回了一個閉包時,這個函數的做用域將會一直在內存中保存,直到閉包不存在爲止。code
瞭解了閉包的特性,咱們就能夠更好理解閉包有那些用途了,由於用途的實現是依賴於閉包的特性。對象
(1)模仿塊級做用域ip
function outputNumbers(count){//沒有閉包 for (var i=0; i < count; i++){ alert(i); } alert(i); //count } outputNumbers(5);
輸出結果:0,1,2,3,4,5是alert(i)輸出的。內存
for執行完了,i 仍是存在於函數做用域中。作用域
function outputNumbers(count){ (function () {//閉包函數,且當即執行 for (var i=0; i < count; i++){ alert(i); } })(); alert(i); //ReferenceError: i is not defined,出現錯誤了 outputNumbers(5);
輸出結果:0,1,2,3,4get
因爲for在一個閉包函數裏,當閉包函數執行完了,i也就銷燬了,因此再在外部函數做用域在使用它就會出現未定義的狀況了。
(2)建立私有變量
利用私有變量特性,咱們就能夠隱藏那些不該該被直接修改的數據了
私有變量定義:任何在函數中定義的變量,均可以認爲是私有變量,由於不能在函數外部訪問這些變量。私有變量包括函數的參數,局部變量和在函數內部定義的其餘函數。
示例:
function add(num1,num2){ var sum=num1+num2; return sum; }//num1,num2,sum都是私有變量
私有做用域(塊級做用域):只在內部可使用,外部沒法訪問
示例:
//建立私有做用域 (function(){ //這裏是私有做用域 })();//正確 //錯誤方法 function(){ //這裏是私有做用域 }();//出錯
JavaScript將function關鍵字看成一個函數申明的開始,而函數申明背後不能更圓括號,然而,函數表達式的後面能夠跟圓括號,要將函數申明轉換成函數表達式,只要將其放在一對圓括號中便可。
特權方法:咱們把有權訪問私有變量和私有函數的公有方法叫作特權方法。
示例:
function Person(name){//name是私有變量 this.getName = function(){//特權方法 return name; }; this.setName = function (value) { name = value; }; } var person = new Person("Nicholas"); alert(person.getName()); //"Nicholas" person.setName("Greg"); alert(person.getName()); //"Greg"
上面示例中的getName()和setName()均可以在外部使用,都有權訪問私有變量name。除了使用構造函數內部定義的這兩個方法外,外部沒有其餘的任何辦法能夠訪問name。
可使用構造函數模式,原型模式來實現自定義類型的特權方法,也可使用模塊方式,加強的模塊方式來實現單例的特權方法。