Private Members in JavaScriptJavaScript中的私人成員
Douglas Crockford
www.crockford.com
翻譯:袁曉輝(blog.csdn.net/uoyevoli/)
JavaScript is the world's most misunderstood programming language. Some believe that it lacks the property of information hiding because objects cannot have private instance variables and methods. But this is a misunderstanding. JavaScript objects can have private members. Here's how.
JavaScript是世界上誤解最深的語言。有人認為它缺少資訊隱藏的能力,理由是它的對象不能擁有私人(private)的變數和方法。但是這是一種誤解。JavaScript對象也有私人成員。方法就在這裡。
Objects
對象
JavaScript is fundamentally about objects. Arrays are objects. Functions are objects. Objects are objects. So what are objects? Objects are collections of name-value pairs. The names are strings, and the values are strings, numbers, booleans, and objects (including arrays and functions). Objects are usually implemented as hashtables so values can be retrieved quickly.
JavaScript是植根於對象的。數組是對象,函數是對象,對象是對象。那麼究竟什麼是對象呢?對象就是一個集合,其中包含“名稱-值”的映射。名稱是字串,值可以是字串,數字,邏輯值或對象(包括數組和函數)。對象通常用雜湊表來實現,以便能快速獲得值。
If a value is a function, we can consider it a method. When a method of an object is invoked, the this variable is set to the object. The method can then access the instance variables through the this variable.
如果一個“值‘是函數,我們叫它方法,當一個對象的方法被調用時, 這個對象就被賦值給this 變數。這樣方法就可以通過this來訪問對象執行個體的變數了。
Objects can be produced by constructors, which are functions which initialize objects. Constructors provide the features that classes provide in other languages, including static variables and methods.
對象可以由建構函式產生,建構函式是用來初始化對象的函數。建構函式在這裡扮演了其他語言中“類”扮演的角色,也提供了定義static變數和方法的手段。
Public
公開
The members of an object are all public members. Any function can access, modify, or delete those members, or add new members. There are two main ways of putting members in a new object:
對象的所有成員都是公開(public)成員。任何函數都可以訪問、修改和刪除這些成員或添加新成員。向一個新的對象中新增成員主要有兩種方式:
In the constructor
在建構函式中
This technique is usually used to initialize public instance variables. The constructor's this variable is used to add members to the object.
function Container(param) {
this.member = param;
}
So, if we construct a new object
var myContainer = new Container('abc');
then myContainer.member contains 'abc'.
這種技術通常用來初始化公開(public)的執行個體變數。建構函式使用this變數來向對象中新增成員。
function Container(param) {
this.member = param;
}
如果我們構造了一個新的對象
var myContainer = new Container('abc');
那麼myContainer.member 將包含 'abc'
In the prototype
在原型(prototype)中
This technique is usually used to add public methods. When a member is sought and it isn't found in the object itself, then it is taken from the object's constructor's prototype member. The prototype mechanism is used for inheritance. It also conserves memory. To add a method to all objects made by a constructor, add a function to the constructor's prototype:
Container.prototype.stamp = function (string) {
return this.member + string;
}
So, we can invoke the method
myContainer.stamp('def')
which produces 'abcdef'.
這種技術通常用來添加公開(public)方法。當(JavaScript解譯器)遇到一個對象的成員,發現它在對象自身中並不存在時,就會到物件建構函數的prototype中去找。這種prototype機制可以用來實現繼承。它同樣佔用記憶體。如果想要給某個建構函式產生的所有對象都添加一個方 法,只要給建構函式的prototype添加這個方法就可以了。
Container.prototype.stamp = function (string) {
return this.member + string;
}
我們調用這個方法
myContainer.stamp('def')
將返回'abcdef'。
Private
私人
Private members are made by the constructor. Ordinary vars and parameters of the constructor becomes the private members.
function Container(param) {
this.member = param;
var secret = 3;
var self = this;
}
私人(Private)成員是由建構函式產生的。普通的(var定義的)變數和參建構函式的參數會成為私人(private)成員。
function Container(param) {
this.member = param;
var secret = 3;
var self = this;
}
This constructor makes three private instance variables: param, secret, and self. They are attached to the object, but they are not accessible to the outside, nor are they accessible to the object's own public methods. They are accessible to private methods. Private methods are inner functions of the constructor.
function Container(param) {
function dec() {
if (secret > 0) {
secret -= 1;
return true;
} else {
return false;
}
}
this.member = param;
var secret = 3;
var self = this;
}
這個建構函式產生了三個私人(private)執行個體變數:param,secret和self。它們是屬於對象的,但是它們對外部是不可見的,對這個對象自身的公開(public)方法也是不可見的。它們對私人(private)方法可見。私人法是建構函式的內建函式。
function Container(param) {
function dec() {
if (secret > 0) {
secret -= 1;
return true;
} else {
return false;
}
}
this.member = param;
var secret = 3;
}
The private method dec examines the secret instance variable. If it is greater than zero, it decrements secret and returns true. Otherwise it returns false. It can be used to make this object limited to three uses.
私人(private)方法 dec 檢查執行個體變數 secret 的值,如果它大於0就減少它的值然後返回true;否則它返回false。它可以用於限制這個對象只能被使用3次。
By convention, we make a private self parameter. This is used to make the object available to the private methods. This is a workaround for an error in the ECMAScript Language Specification which causes this to be set incorrectly for inner functions.
根據慣例,我們產生了一個私人(private)的 self 變數,用於讓私人(private)方法可以訪問對象本身。這是一個變通的解決方案,需要它的根本原因在於ECMAScript語言規範的一個錯誤,而這個錯誤導致內建函式的this變數有錯誤。(譯者註:真的是這樣嗎?根據我的實驗好像不需要這個self變數)
Private methods cannot be called by public methods. To make private methods useful, we need to introduce a privileged method.
私人(private)方法不能被公開(public)方法調用。為了讓私人函數有作用,我們需要引入特權(privileged)方法的概念。
Privileged
特權
A privileged method is able to access the private variables and methods, and is itself accessible to the public methods and the outside. It is possible to delete or replace a privileged method, but it is not possible to alter it, or to force it to give up its secrets.
一個特權(privileged)方法可以訪問私人(private)變數和方法,並且它本身可以被公開(public)方法和外部存取。可以刪除或替換一個特權方法但是不能改變它或強迫它放棄自己的秘密。
Privileged methods are assigned with this within the constructor.
function Container(param) {
function dec() {
if (secret > 0) {
secret -= 1;
return true;
} else {
return false;
}
}
this.member = param;
var secret = 3;
var self = this;
this.service = function () {
if (dec()) {
//譯者註:根據我的實驗
//這裡使用 this.member 也是可以的
return self.member;
} else {
return null;
}
};
}
特權方法是在建構函式通過this賦值的
function Container(param) {
function dec() {
if (secret > 0) {
secret -= 1;
return true;
} else {
return false;
}
}
this.member = param;
var secret = 3;
var self = this;
this.service = function () {
if (dec()) {
return self.member;
} else {
return null;
}
};
}
service is a privileged method. Calling myContainer.service() will return 'abc' the first three times it is called. After that, it will return null. service calls the private dec method which accesses the private secret variable. service is available to other objects and methods, but it does not allow direct access to the private members.
service是一個特權方法。前三次調用myContainer.service()將返回'abc',之後它將返回null。service調用private的dec方法,dec方法訪問private的secret變數。service對其他對象和函數都是可見的,但是它不允許直接存取private成員。
譯者註:
這個有必要嗎?根據我的實驗(IE6和FF1.5.0.3)都可以正常以下代碼:
function Container(param) {
this.member = param;
var secret = 3;
var self = this;
this.service = function () {
if (secret > 0) {
secret -= 1;
return this.member;
} else {
return null;
}
};
}
Closures
閉包
This pattern of public, private, and privileged members is possible because JavaScript has closures. What this means is that an inner function always has access to the vars and parameters of its outer function, even after the outer function has returned. This is an extremely powerful property of the language. There is no book currently available on JavaScript programming that shows how to exploit it. Most don't even mention it.
這種模式的公開(public),私人(private)和特權(privileged)之所以成為可能是因為JavaScript有閉包(closures)。閉包的意思是:一個內建函式總是可以訪問它外層函數的變數和參數,即使外層函數已經返回。這是JavaScript的一個極其強大的特性。目前還沒有如何一本JavaScript編程的書講到如何利用它,其實大多沒用提到它。
Private and privileged members can only be made when an object is constructed. Public members can be added at any time.
私人(private)和特權(privileged)成員只能在對象被構造時產生。公開(public)成員可以在任何時間添加。
Patterns
模式
Public
function Constructor(...) {
this.
membername =
value;
}
Constructor.prototype.membername = value;
Private
function Constructor(...) {
var self = this;
var
membername =
value;
function membername(...) {...}
}
Note: The function statement
function membername(...) {...}
is shorthand for
var membername = function membername(...) {...};
注意:
function membername(...) {...}
是下列語句的簡略形式:
var membername = function membername(...) {...};
Privileged
function Constructor(...) {
this.
membername = function (...) {...};
}
Copyright 2001 Douglas Crockford. All Rights Reserved Wrrrldwide.
著作權
<完>
原文連結:http://www.crockford.com/javascript/private.html
袁曉輝 翻譯 @ 2006-5-19