javascript面向对象的写法02
面向对象特性的初步实现
1.封装 利用作用域封装变量
作用域的概念是一样的,for语句,if语句等这些作用域内定义的变量只能作用域内访问,函数内定义的变量只能函数内访问。
function ClassA() { var a = 1; } var b = a; //无法访问。 var obj = new ClassA(); var c = obj.a; //new出一个对象也无法访问。
但是函数内部是可以访问到的
function ClassA() { var a = 1; var b = a; //内部可以访问 function func1() { a = 100; return a; //函数内部都可以访问,内部函数也能访问外函数的变量; } }
因为内部可访问,外部不可访问。则可以模拟面向对象的私有属性。在函数内部使用var关键字定义变量就可以了。
function ClassA() { var a = 1; //私有属性 private this.b = 100; //公共属性 public }
内部使用var 和使用 this的区别。
this是个指向函数或对象自身的引用。上例中如下写法是一样的作用。
function ClassA() { this.b = 1; } var obj = new ClassA(); //函数可看出构造方法,构造过程this.b = 1这条语句已经执行 //替换写法 function ClassA() { } var obj = new ClassA{}; obj.b = 1; //构造函数为空,于是外面补上设置属性值语句。 alert(obj.b); //此种写法obj.b这个属性变量自然是可以访问到的。
var只是简单的变量定义,上例中只是在函数内部定义了一个变量而已。
//本例中只是在两个不同的作用域空间定义了两个不同变量而已。没有任何关于对象引用的问题。 function ClassA() { var a = 1; } var a = 100;
因此在函数内部使用var 和this定义变量可以模拟public 和private的作用。
但是这种公共变量和私有变量同其他面向对象语言不同的是,其他语言公共和私有变量都是对象真正的属性,只是控制了它的访问权限。但js中公共的变量是对象动态设置的一个属性,真正的属性,但是私有变量只是一个内部的普通变量而已。
如何使用私有变量和公共变量
使用的时候注意,因为私有变量只是一个简单的变量,使用的时候不能加this关键字,公共变量是真正的属性,使用的时候需要加this关键字
function ClassA() { var a = 100; this.b = 200; this.func1 = function() { return a + this.b; //正确用法 }; this.func2 = function() { return a + b; //错误用法,this.b != b, 一个是对象的属性,一个是简单变量 }; this.func3 = function() { return this.a + b; //错误用法,a只是一个简单变量 }; }
公共方法,私有方法
前面提到过js的属性可以存放任意东西,包括函数指针。所以用同样的方式也就可以实现私有方法和公共方法。
同样方法和简单变量一样,也是同样的var和this写法做到私有方法和公共方法
function ClassA() { var func1 = function(){}; //私有方法 this.func2 = function(){}; //公共方法 }
内部使用的时候同样是公共的加this,私有方法不加this直接当普通函数使用。
function ClassB() { var func1 = function(){}; this.func2 = function(){}; this.func3 = function() { func1(); this.func2(); }; }
注意,同其他语言不通私有方法不能访问公共方法和公共变量。因为私有方法本质上只是个普通的方法,只是他定义在函数对象内部而已。除了位置在函数对象内部外,其他跟函数对象没任何关联。
function ClassA() { this.a = 100; var func1 = function(){ alert(this.a); //不能访问,此时this指的是func1这个普通函数对象 this.func2(); //不能访问,此时this指的是func1这个普通函数对象 }; this.func2 = function(){}; }
不管公共方法还是私有方法都只能在函数内部访问私有变量和私有方法。
function ClassB() { var a = 100; var func1 = function(){ alert(a); }; this.func2 = function() { func1(); //正常访问 return a; //正常访问 }; } var obj = new ClassB(); alert(obj.a); //无法访问 obj.func1(); //无法访问
私有变量的设计只是为了防止在对象外部被随意乱修改,并不是拒绝外部不能访问。
那么如何在函数外部访问私有成员变量呢?利用公共方法配合。下例演示一个常见的get和set方法
function ClassA() { var a = 100; //私有成员属性 this.getA = function(){ //公共get方法 return a; }; this.setA = function(value){ //公共set方法 return a = value; }; } var obj = new ClassA(); alert(obj.getA()); obj.setA(500);
公共方法,因为其定义在函数内部,函数内部定义的变量是可以访问到的。因为其本身是公共方法,可以被外部访问,这样便可以做到外部代码通过公共方法访问私有成员变量。
封装属性的设计是为了保护对象的完整性,也就是防止胡乱修改。上例这种做法可以做到真正的私有。但是有时候为了简化代码不这样做,而是用更简洁的方式达到。为每个变量名前面加一个下划线,向其他程序员表示这个是私有变量不好随意修改。其他程序员遵照原作者意图不去修改,这样通过一种默契的配合也实现了同样的结果。有一些面向对象语言也是没有private变量的概念,比如python,他们也大多采用加下划线的方式表示它是私有变量。
function ClassA() { this._a = 100; //文档化的私有成员属性 } var obj = new ClassA(); obj._a = 100; //看到下划线前缀的变量,这样的操作是不应该的。