[原]Java程序員的JavaScript學習筆記(4——閉包/getter/setter)


計劃按以下順序完成這篇筆記:
安全

  1. 理念。
  2. 屬性複製和繼承。
  3. this/call/apply。
  4. 閉包/getter/setter。
  5. prototype。
  6. 面向對象模擬。
  7. jQuery基本機制。
  8. jQuery選擇器。
  9. jQuery工具方法。
  10. jQuery-在「類」層面擴展。
  11. jQuery-在「對象」層面擴展。
  12. jQuery-擴展選擇器。
  13. jQuery UI。
  14. 擴展jQuery UI。

這是筆記的第4篇,聊聊閉包/getter/setter,看看JavaScript中的變量做用域和實現封裝的方法。

閉包


做者博客:http://blog.csdn.net/stationxpapp

做者微博:http://weibo.com/liuhailong2008函數

轉載請取得做者贊成工具



一、閉包

閉包是JavaScript一項簡單實用的語言特性。經過閉包:
彌補了函數沒有public/private等訪問訪問權限控制符的缺陷,保護了函數內部變量的安全。
使得函數對象在做爲參數傳遞時,不只僅傳遞運算邏輯,同時也傳遞了相關變量。
使得函數「類」的不一樣實例,獨享本身的屬性。
下面逐個來看。
ui

1.一、保護私有變量

1.1.一、原理

閉包最主要的特性是:當函數做爲返回值時,連同函數定義時的環境(包括函數外部,函數能夠訪問到的變量)一塊兒返回,確保這些變量不因其依附的對象銷燬而被銷燬。
有點兒繞,具體什麼意思呢?看下面的代碼:
// 代碼段1
 function UiObject() {
     var childCount = 0; // 函數內部變量,  
     return 0;
 }
 
 var funcReturnValue = UiObject();  // 調用函數,返回0
 console.log(UiObject.childCount);   // 輸出:undefined,因爲函數調用完成,內部變量已經被銷燬
 
 childCount隨着UiObject函數的調用結束而銷燬,從另外一個角度看,保護了函數內部的變量。
 在這個基礎上,若是咱們有一種辦法能夠確保函數的內部變量不被銷燬,並且提供方法對其訪問操做,也就實現了經過public方法訪問 private 變量。
 代碼以下:
 // 代碼段2
 function UiObject() {
     var childCount = 0; // 函數內部變量
     function getChildCount(){
         childCount = 6;
         return childCount;
     }
     return getChildCount;
 }
 var funcReturnFObject = UiObject();  // 調用函數,返回 getChildCount 函數,返回值是一個閉包
 console.log(funcReturnFObject());   // 輸出:6
 下面咱們就看看,若是利用閉包的這一特性實現對私有屬性的保護。
 
 
this

 1.1.二、語法

 在代碼段2的基礎上改進,代碼段3展現的代碼,能夠同時提供多個方法,對私有屬性訪問。
 //代碼段3
 function UiObject() {
     var childCount = 0; // 函數內部變量
     
     return {
         getChildCount : function (){
             return childCount;
         },
         setChildCount : function (cnt){
             childCount = cnt;
         }
     };
 }
 
 var o = UiObject();  // 調用函數,返回 getChildCount 函數,返回值是一個閉包
 o.setChildCount(6);
 console.log(o.getChildCount());   // 輸出:6
 
 思考: 若是 var childCount = 0 ; 改成 this.childCount = 0; 呢?
 咱們以前研究過this,「 this.childCount = 0; 」語句是將childCount附加爲調用者的屬性,this.childCount的將生命週期與調用者相同。這與閉包不衝突。
 
 代碼段3還能夠寫成代碼段4的形式。
 
 // 代碼段4
 function UiObject() {
     var childCount =  0; // 函數內部變量
     this.setChildCount = function(cnt){
         childCount = cnt;
     };
     this.getChildCount = function(){
         return childCount;
     };
 }
 
 var ui = new  UiObject();          // 調用函數,返回retObj
 console.log(ui.childCount);       // 輸出:undefined,因爲函數調用完成,局部變量已經被銷燬
 ui.setChildCount(3);                  // 因爲閉包的做用,ui仍然保存着變量childCount,並對其操做
 console.log(ui.getChildCount()); // 輸出:3
 
 「this.setChildCount = function(cnt){       childCount = cnt;   };」 這個語句至關於在UiObject內部定義了函數並「傳遞」了給ui對象。一樣產生了閉包。
 
spa

1.二、傳遞函數時,同時傳遞上下文

經過上面的例子,咱們已經看到了這點特性。
在具體的應用場景中可對其大加利用。

.net

1.三、不一樣實例,獨享本身的變量

咱們已經知道了,函數在傳遞過程當中,會產生一個閉包。對於同一方法產生的閉包,是相同的,仍是爲每次傳遞建立了不一樣的拷貝呢?
看下面的代碼:
//代碼段5
 function UiObject() {
     var childCount = 0; // 函數內部變量
     
     return {
         getChildCount : function (){
             return childCount;
         },
         setChildCount : function (cnt){
             childCount = cnt;
         }
     };
 }
 
 var ui1 = UiObject();
 var ui2 = UiObject();
 
 ui1.setChildCount(1);
 ui2.setChildCount(2);
 
 console.log(ui1.getChildCount()); // output : 1
 console.log(ui2.getChildCount()); // output : 2
 
 每次生成閉包是不一樣的拷貝。
 
 思考:對比Java,加深理解。
 
 

prototype

二、getter/setter


JavaScript
 //代碼段6
 var uiPanel ={
     _type  : 'Panel',
     _width : -1,
     _height: -1,
     
     get type(){ return this._type;},
     
     get width(){ return this._width; },
     set width(v){this._width = v;},
     
     get height(){ return this._height; },
     set height(v){this._height = v;}
 };
 
uiPanel.type = 'TextField';          // does not work
console.log('type:'+uiPanel.type); // ouput :         type:Panel
 
 uiPanel.width = 800;                 //
 console.log('width:'+uiPanel.width); // ouput :         width:800

語法上愈加有面向對象的範兒了。
除了在定義時經過set/set關鍵字控制屬性的讀寫權限。還能夠在運行期經過 Object.defineProperty()函數動態添加屬性,並提供更精細的控制。
代碼以下(如下代碼均未經實驗):
var o = {};
Object.defineProperty(o,'propName',{
            value:1,  //屬性的值,也能夠經過   get:function(){retun x;}的方法設定
            writeable:true,//是否能夠經過o.propName  = newValue ; 的方法設置屬性的值
            enumerable:false,//是否能夠經過被枚舉
            configurable:true//是否能夠經過defineProperty配置
    });
另外,還有一系列API能夠完成對屬性的配置、檢測。以下:
Object.getOwnPropertyDescriptor{{x:1},"x"}
Object.keys(obj);    // 得到對象上全部可枚舉的「實例屬性」
Object.getOwnPropertyNames(obj) ;//得到對象上全部的「實例屬性」
obj.hasOwnProperty(‘id’); //只要該對象obj擁有屬性id, 不管id是否可枚舉,都返回true


三、小結

當大多數人已經習慣了面向對象的思惟和方法,語言就要從特性方面予以知足,這不合理,也不美。但世界就是如此不完美。

JavsScript天生麗質,非要把她改形成機甲戰士,那之後誰來負責傾國傾城呢?

ECMAScript 5不是革命性創新,也不是救命稻草這個世界原本能夠更好的。




做者:stationxp 發表於2014-10-17 3:40:37 原文連接
閱讀:384 評論:0 查看評論
相關文章
相關標籤/搜索