2007年3月13日

JavaScript中的私有成员

JavaScriptJavaScript 世界上最被误解的程序设计语言。一些人认为它缺乏信息隐藏的特性,因为对象不能有私有的实例变量和方法,但实际上这是一种误会,JavaScript对象可以有私有成员,这篇文章将描述这样的情形。

对象

对象objects是JavaScript的根基,数组是对象,函数是对象,对象是对象。但是对象是什么呢?对象是键/值对的集合,键是字符串,值是字符串、数字、布尔值和对象(包括数组和函数)。对象以哈希表的方式实现,所以值容易被迅速地找到。

如果一个值是一个函数,我们可以认为它是一个方法,当一个对象的方法被调用的时候,this变量指向了该对象,方法可以通过this变量存取该对象的实例变量。

对象可以由构造器来产生,也就是那些初始化对象的函数们。构造器提供了像其他语言类提供的特性,包括静态的变量和方法。

公有成员

一个对象的所有成员都是公有成员,任何函数都可以存取、修改或删除这些成员,又或者增加新的成员。把成员放入一个对象中主要有有2种方式:

在构造器中

这种方式通常是被用于初始化公共实例变量,构造器的this变量被用于增加对象的成员。

function Container(param) {
    this.member = param;
}

这么说来,如果我们构造一个新对象

var myContainer = new Container('abc');

那么myContainer.member就包含'abc'了。

在原型中

这种方式经常用来增加公有方法,当一个成员被找到,但不是在对象本身上找到的,那么它是从对象构造器的原型成员上带来的。原型机制被用于继承,这也避免浪费内存。使用构造器为所有的对象增加方法,只要为构造器的原型增加一个函数就可以了:

Container.prototype.stamp = function (string) {
    return this.member + string;
}

所以我们可以这样地触发此方法

myContainer.stamp('def')

其结果为'abcdef'

私有成员

私有成员由构造器创建,普通的var声明和参数构成了私有成员

function Container(param) {
    this.member = param;
    var secret = 3;
    var that = this;
}

这个构造器有3个私有的实例变量:paramsecretthat。它们被附着在对象上,但是他们与外界不直接相互存取,他们也不能与对象本身的公有方法相互存取(译者按:这里的公有方法应该是指那些通过原型实现的方法),他们可以与私有方法相互存取。私有方法指的是那些构造器内的内部方法。

function Container(param) {

    function dec() {
        if (secret > 0) {
            secret -= 1;
            return true;
        } else {
            return false;
        }
    }

    this.member = param;
    var secret = 3;
    var that = this;
}

私有方法dec间车secret实例变量,如果它比0大,它就减1并且返回true,否则返回false这可以用于保证对象3次以内的调用。

根据习惯,我们创建了一个私有的that成员,这使对象的私有方法可以使用对象实例了,这是对ECMAScript语言规范对于内部方法把this设置为一个不正确的值的一种回旋。

私有方法不能被公有方法(译者按:这里的公有方法应该是指那些通过原型实现的方法)直接调用,为了使私有方法变的有用,我们需要引入一个特权方法

特权方法

一个特权方法可以存取私有变量和私有方法,并且它本身与公有方法及外部可以相互存取,删除和替换一个特权方法是可行的,但是改变它特性或者强迫放弃它的秘密都是不可能的。

特权方法是指那些在构造器中与this关联的方法。

function Container(param) {

    function dec() {
        if (secret > 0) {
            secret -= 1;
            return true;
        } else {
            return false;
        }
    }

    this.member = param;
    var secret = 3;
    var that = this;

    this.service = function () {
        if (dec()) {
            return that.member;
        } else {
            return null;
        }
    };
}

service就是一个特权方法。在前三次的调用myContainer.service()中,将会返回'abc',之后将返回nullservice调用了私有方法dec,就是那个可以存取私有变量secret的方法。service对于其他的对象和方法是可用的,但是它不允许直接存取私有成员。

闭包

这种公有,私有和特权成员的方式是可行的,因为JavaScript拥有闭包。这句话的意思是说一个内部函数总是有权访问它外部函数变量和参数,甚至是在外部函数已经返回之后。这是该语言一个非常强大的特性,没有一本关于JavaScript书谈论了如何“开采”它,大多数书根本没有提及到它。

私有和特权成员只有在对象被创建的时候产生,公有成员可以在任何时间增加。

套路

公有方法

function Constructor(...) { 
    this.membername = value;
}
Constructor.prototype.membername = value;

私有方法

function Constructor(...) { 
    var that = this;
    var membername = value;
    function membername(...) {...}
}

注意这个函数语句

function membername(...) {...}

是对如下的简写

var membername = function membername(...) {...};

特权方法

function Constructor(...) {
    this.membername = function (...) {...};
}
特别声明,文章翻译于Private Members in JavaScript
版权由原作者所有。

没有评论: