首页 » 编写高质量代码:改善JavaScript程序的188个建议 » 编写高质量代码:改善JavaScript程序的188个建议全文在线阅读

《编写高质量代码:改善JavaScript程序的188个建议》建议100:谨慎使用类的静态成员

关灯直达底部

在面向对象的编程中,类是不能够直接访问的,必须实例化后才可以访问,但静态属性和方法与类本身直接联系,可以直接通过类来访问。例如,JavaScript核心对象中的Math和Global都是静态对象,不需要实例化就可以直接访问。

类的静态成员包括私有和公共两种类型,不管是公共成员还是私有成员,它们在系统中只有一份副本,不会被分成多份传递给不同的对象,而是通过函数指针进行引用,这与闭包截然不同。下面示例为类型定义一个私有的静态成员。


var F=(function{

var_a=1;//私有变量

this.a=_a;//公共属性

this.get1=function{//公共方法

return_a;

};

this.set1=function(x){//公共方法

_a=x;

};

return function{//构造函数类

this.get2=function{//提供访问私有变量的接口

return_a;

};

this.set2=function(x){//提供修改私有变量的接口

_a=x;

};

}

});

//定义类的静态公共方法和属性

F.get3=function{

return get1;

};

F.set3=function(x){

set1(x);

}


与一般类的创建方法一样,这里的私有成员和特权成员仍然被声明在构造器中,并借助var和this关键字来实现。这里的构造器却由原来的普通函数变成了一个内嵌函数,并且作为外层函数的返回值赋值给了变量F,这就创建了一个闭包。在这个闭包中,还可以声明静态私有成员,例如:


var F=(function{

function set5(x){//静态私有方法

_a=x;

}

function get5{//静态私有方法

return_a;

}

});


这些静态私有成员可以在构造器内部访问,这意味着所有私有函数和特权函数都能访问它们。与其他方法相比,静态方法有一个优点,那就是在内存中仅存放一份。那些被声明在构造器之外的公共静态方法,以及下文中将要提到的F类原型属性都不能访问在构造器中定义的任何私有属性,因此它们不是特权成员。

定义在构造器中的私有方法能够调用其中的静态私有方法,反之则不然。要判断一个私有方法是否应该被设计为静态方法,可以看它是否需要访问任何实例数据。如果它不需要,那么将其设计为静态方法会更有效率,因为它只被创建一份。

定义类的静态公共方法和属性一般在类的外面进行,这种外挂定义的方式在前面的示例中也曾经介绍过。这种外挂的静态方法和属性可以直接访问,这实际上相当于把构造器作为命名空间来使用。同时,由于它们仍然属于构造器结构的一部分,因此在这些静态方法和属性中可以访问闭包中的私有成员。


alert(F.get3);//直接访问类F的静态方法get3,返回1

F.set3(2);//修改私有变量的值

alert(F.get3);//2,说明修改成功


注意,类F是返回的内层函数,该值是一个构造函数,它无法访问外层函数的公共方法get1和set1,但能够访问返回构造函数体内的公共方法get2和set2。例如:


var a=new F//实例化类F

alert(a.get2);//调用类F的公共方法get2,返回1

a.set2(2);//调用类F的公共方法set2,修改私有变量_a

alert(a.get2);//调用类F的公共方法get2,返回2


但下面的用法都是错误的,因为级别比较低的F类(F是返回的匿名构造函数)无权访问闭包体内的变量、属性和方法(不管是私有的还是公共的)。


var a=new F

alert(a.get1);

a.set1(2);

alert(a.get1);


闭包体内的所有对象都可以访问闭包体内的私有或公共变量、属性和方法。由于类F是闭包体内返回的构造函数,因此根据作用域链,它们可以向上访问闭包所有成员。


F.prototype={//类F的原型对象

get4:function{//原型方法get4

return get1;//访问闭包内数据

},

set4:function(x){//原型方法set4

set1(x);//访问闭包内数据

}

};

var a=new F;//实例化类F

alert(a.get4);//1