[翻译]JS中的私有成员

翻译自:Private Members in JavaScript http://www.crockford.com/javascript/private.html

作者虽然写于早年,但还是挺有参考价值和值得学习的。

JavaScript中的私有成员

      JavaScript是世界上被误解最深的程序设计语言。一些人认为它缺乏信息隐藏(information hiding)的特性,理由是对象不能有私有实例变量和方法。但其实这是误解,JavaScript对象可以有私有成员。以下就是解释。

     对象Objects

     JavaScript的本质就是对象。数组是对象,函数是对象,对象是对象。那么什么事对象呢?对象就是名值对(name-value pairs)的集合。名是字符串(string),值是字符串、数值、布尔值或对象(包括数组和函数)。对象通常被实现为哈希表的方式以便其值能快速被获取到。

     如果值是一个函数(function),我们可以称之为一个方法(method)。当一个对象的某个方法被调用时,变量this就会被配置到该对象上,方法就能通过this变量来方法实例变量。

     对象可用通过构造器(constructor)创建,构造器就是能初始化对象的函数。构造器表现出了一些其他语言中类的特征,包括静态变量和方法。

      公开Public

     一个对象的成员全部都是公开成员(public member)。任何函数都可以访问、修改或删除这些成员。有两种主要方式把成员放到一个新对象中。

      方法1:在构造器中(In the constructor

      这个技术通常用来初始化公开的实例变量。构造器的this变量要用于指明把成员添加给对象。

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

     那么,如果我们这样构造一个新对象:

     var myContainer = new Container('abc');

     然后,myContianer.member的值就是'abc'。

     方法2:在原型中(In the prototype

      这个技术通常用来初始化公开的方法。当查找一个成员且在对象本身中找不到时,就从对象的构造器的原型prototype成员中去找。原型机制被用于继承,也可以存储。为了通过一个构造器给所有对象添加一个方法,我们可以给构造器的prototype属性添加一个函数:

     

Container.prototype.stamp = function (string) {
    return this.member + string;
}
     那么,我们可以这样调用这个方法:

     myContainer.stamp('def');

     将返回'abcdef'.

      

      私有Private

     私有成员由构造器来创建。普通的var变量和构造器的参数就是私有成员。

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

    这个构造器创建出了3个私有的实例变量:param,secret和that。它们都依附于该对象,但都不能在对象外部被访问,也不能被对象自己的公开方法所访问。他们只能对私有方法可见。私有方法是构造器的内部函数。

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在函数的内部函数被不正确地指向window。    如以下代码:

    //本文译者引入的一个例子

function a(){   
	console.log(this);  //a {}
	function b(){     
		console.log(this);  //window   
	}   
	b(); 
} 

new a();

     但是,此问题在严格模式已被修改。使用暂存方式,仅在非严格模式中运用。     

     私有方法不能被公开方法调用。为了使得私有方法有用,我们需要引入一个授权方法(privileged method)。

   

    授权Privileged

    授权方法能够访问私有变量和方法,它本身对公开方法和对象外部是可访问的。可以删除或替换一个授权方法,但不可能修改它,或者使它放弃其秘密(这里的本意是指授权方法的本质是能获得对象私有的内容)。

    授权方法通过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 () {
        return dec() ? that.member : null;
    };
}

    这里service就是一个授权方法。调用myContainer.service()将在三次调用的第一次时返回'abc',之后返回null。service调用了私有的dec方法,dec内有访问了私有的secret变量。service对于其它对象和方法是可用的,但是它不允许直接访问私有成员。

    闭包Closures

     公开、私有和授权成员是可行的,原因在于JavaScript·有闭包(Closures)。这意味着一个内部函数总是能访问var和外部函数的参数,甚至在外部函数返回之后。这是语言一种十分有力的特性。(注:这里有一句省略,大意是说作者写作时很少有书提到闭包概念,更不用说进一步探讨)

    模式Patterns

     Public

     

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

    Private

    

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

    注意:函数语句

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

    是以下语句的简写:

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

    也就是说membername其实也是var声明的私有成员(方法) 

     Privileged

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

相关推荐