衆所周知,JavaScript沒有塊級做用域,只有函數做用域。那就意味着定義在函數中的參數和變量在函數外部是不可見的,而在一個函數內部任何位置定義的變量,在該函數內部任何地方均可見。這帶來的好處是內部函數能夠訪問定義它們的外部函數的參數和變量。javascript
首先,咱們來構造一個簡單的對象。java
1 var testObj = { 2 value: 10, 3 add: function(inc){ 4 this.value += (typeof inc === "number") ? inc : 1; 5 } 6 }; 7 8 testObj.add(); 9 testObj.value; // 11 10 11 testObj.add(2); 12 testObj.value; // 13
這樣寫就有一個問題,value值不能保證不會被非法修改,能夠按以下的方法進行修改。閉包
var testObj = (function(){ var value = 10; return { add: function(inc){ value += (typeof inc === "number") ? inc : 1; }, getValue: function(){ return value; } }; })(); testObj.add(); testObj.getValue(); // 11 testObj.add(2); testObj.getValue(); // 13
咱們能夠通用調用一個函數的形式去初始化testObj,該函數會返回一個對象字面量,函數裏定義了一個value變量,該變量對add和getValue方法老是可用的,但函數的做用域使得它對其餘的程序來講是不可見的。同時,咱們還能夠得出一個結論,內部函數擁有比它的外部函數更長的生命週期。函數
咱們再繼續看一個構造函數調用的例子。this
var MyObj = function(str){ this.status = str; }; MyObj.prototype.getStatus = function(){ return this.status; }; var obj = new MyObj("javascript"); obj.getStatus(); // "javascript"
這樣寫並無錯,可是會有一點「畫蛇添足」,爲何要用一個getStatus方法去訪問一個本能夠直接訪問到的屬性呢?若是status是私有屬性,那固然纔有意義。spa
var obj = function(status){ return { getStatus: function(){ return status; } }; }; var myObj = obj("javascript"); myObj.getStatus(); // "javascript"
這裏當咱們調用obj的時候,它返回包含getStatus方法的一個新對象,該對象的一個引用保存在myObj中,即便obj已經返回了,但getStatus方法仍然享有訪問obj對象的status屬性的特權。getStatus方法並非訪問該參數的一個副本,它訪問的就是該參數自己。這是可能的,由於該函數能夠訪問它被建立時所處的上下文環境,這被稱爲閉包。prototype