zoukankan      html  css  js  c++  java
  • 深入理解JavaScript模拟私有成员

      一般的面向对象语言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,这个闭包是无法避免的。

  • 相关阅读:
    第二章 Centos7下Confluence7.4.0安装
    第一章 APM基本介绍
    第二十一章 MySQL导入数据常见报错解决
    第二十章 Centos7 下 Mysql 8.0.24编译安装
    第一章 Confluence基础介绍
    第十九章 Centos7下 Mysql 8.0.24 二进制安装
    团队项目冲刺阶段一(5)
    团队项目冲刺阶段一(4)
    团队项目冲刺阶段一(3)
    团队项目冲刺阶段一(2)
  • 原文地址:https://www.cnblogs.com/goloving/p/7087730.html
Copyright © 2011-2022 走看看