1. 程式人生 > >深入理解JavaScript模擬私有成員

深入理解JavaScript模擬私有成員

全局變量 truct 以及 pre 成員 fun process 通過 str

  一般的面向對象語言C++或JAVA,對象都是有私有成員的。js中沒有類的改變,同樣也沒有對象的私有成員這個概念。但是可以通過某些特殊寫法,模擬出私有成員。

1、特權模式:

  (1)在構造函數內部聲明的變量、子函數以及參數,全部都是函數私有的,可以看作私有成員。給this指針添加的閉包,全部都是公有成員

  所以下面例子:參數a/b、變量_value、函數add是私有的,外面無法訪問,故c1.add會報錯

  setValue和getValue是公有的,c1可以訪問

function MyClass(a,b){  
    //private  
    var _value=0;  
    function add(){  
        _value
=a+b; } //process add(); //public this.getValue=function(){ return _value; } this.setValue=function(a1,b1){ a=a1; b=b1; add(); } } var c1=new MyClass(1,2); var c2=new MyClass(1,2); c1.setValue(3,4); alert(c1.getValue());
//7 alert(c2.getValue());//3 alert(c1.add());//c1中無add方法,報錯c1.add is not a function(…)

  (2)這種模擬方法的優點是代碼清晰明了,缺點是每個對象的成員函數,不論是私有還是公有,都是自己獨有的即便成員函數的功能相同,但他們卻是存放在不同位置的不同函數。
  (3)這種模擬方法只模仿了一個外形。OOP語言中,每個對象的成員函數,在內存中只體現為一個單元,我們違背了這一原則

2、私有作用域模式:

  (1)既然模擬出了塊級作用域,可以考慮把塊級作用域拿來,模擬一下私有成員。

(function(){  
    
//private var _value=0, _a=0, _b=0; function add(){ _value=_a+_b; } //construct MyClass=function(a,b){ _a=a; _b=b; add(); } //public MyClass.prototype.getValue=function(){ return _value; } MyClass.prototype.setValue=function(a1,b1){ _a=a1; _b=b1; add(); } })(); var c1=new MyClass(1,2); var c2=new MyClass(1,2); c1.setValue(3,4); alert(c1.getValue());//7 alert(c2.getValue());//7 alert(c1.add());//報錯

  (2)上面例子我們使用了塊級作用域_value、_a、_b、add都是匿名函數的私有變量MyClass前面沒有var,所有MyClass是全局變量,可以在塊級作用域外部使用getValue和setValue是通過原型模式為MyClass添加的公共方法
  (3)這樣寫,MyClass所有實例的公共方法不再單獨創建,而是共享使用;而私有方法,則是共享作用域鏈中的add,也不是獨立創建的。針對成員方法而言,已經與C++和java非常接近了。
  (4)但這樣寫的缺點也是顯而易見的就是私有數據成員_value、_a、_b在各實例之間也是共享的。這些成員,相當於static成員

3、綜合模式

(function(){     
    //private static  
    var _count=0;  
    function add(a,b){  
        return a+b;  
    }  
    //construct  
    MyClass=function(a,b){  
        //private  
        var _data={ value:0 }  
        //process  
        _data.value=add(a,b);  
        _count++;  
        //public  
        this.data=function(){return _data;}  
    }  
    //public  
    MyClass.prototype.getValue=function(){  
        return this.data().value;     
    }  
    MyClass.prototype.setValue=function(a,b){  
        this.data().value=add(a,b);  
    }  
    MyClass.prototype.getCount=function(){  
        return _count;    
    }  
})();  
  
var c1=new MyClass(1,2);  
var c2=new MyClass(1,2);  
c1.setValue(3,4);  
alert(c1.getValue());//7  
alert(c2.getValue());//3  
alert(c1.getCount());//2  
alert(c2.getCount());//2   

  (1)為了解決私有作用域模式中私有數據成員共享的問題,必須將私有數據成員寫在MyClass內。但這樣,公有成員函數就不能使用他們了。所以還是要使用一個特權函數,提供私有數據成員的接口,這個是無法避免的,因此只能讓代價盡量的小,比如對私有數據成員做一個打包。
  (2)私有方法是內存共享的,比如add函數。然而實際上,私有方法只要共享內存,就是private static狀態,而private static狀態方法,如果想使用非形參變量時,也只能使用private static的變量,比如_count。想使用實例的私有數據成員,只能通過形參傳入。
  (3)公有方法是內存共享的,是通過原型鏈實現的。公有方法使用私有數據成員,就必須得到私有數據成員的接口。我們做的this.data就是接口
  (4)整個模式中,閉包個數只有一個,就是this.data,這個閉包是無法避免的。

深入理解JavaScript模擬私有成員