JavaScript中的私有成員




JavaScript是世界上最受誤解的語言。有人認爲它缺少信息隱藏的屬性(封裝),因爲JavaScript對象不能擁有私有變量和函數。但這是誤解。JavaScript對象可以有私有成員。下面進行說明。

對象

JavaScript操作都是關於對象的。數組(Array)是對象,函數(Function)是對象。Object(類型)是對象。那麼什麼是對象呢?對象就是“名稱-值”對(name-value)。名稱是字符串,值可以是字符串、數值、布爾值或對象(包括數組和函數)。對象經常用哈希表實現,所以取值速度很快。

如果對象的一個值是函數(function),我們可以認爲它是成員函數,當成員函數被調用時,this變量就會指向該對象。成員函數可以通過this變量訪問對象的成員。

對象可以通過構造器(constructor)生成,構造器是個初始化對象的函數。構造器在這裏扮演了其他語言中“類”扮演的角色,也提供了定義static變量和方法的手段。


Public成員

對象的所有成員都是公開成員,誰都可以讀寫甚至刪除這些成員或添加新成員。添加新成員有兩種方法:

在構造器裏添加

這通常被用來初始化公開的成員變量。利用構造器的this變量來把成員添加到對象裏。

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

用下面這行代碼生成一個對象實例

  1. var myContainer = new Container('abc');

myContainer的member成員值爲'abc'。


在原型中添加

這種方法經常用來添加公開成員函數。當Javascrīpt解釋器遇到一個對象的成員,發現對象自身中並不存在這個成員時,就會到對象構造函數 的原型中去找。原型機制可以用來實現繼承。它同樣佔用內存。如果想要給某個構造函數生成的所有對象都添加一個方 法,只要給對象的原型添加這個方法就可以了。

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

這樣就可以調用這個成員函數

  1. myContainer.stamp('def')

返回值'abcdef'。


私有成員

私有成員是在構造器裏產生的。var定義的變量和構造器的參數會成爲私有成員。

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

這個構造器定義了三個私有變量:param,secret和self。它們屬性對象Container,而對象外的代碼或是對象的公開方法都無法訪問它們。

只有私有方法可以訪問。私有方法是構造器內定義的函數。

  1. function Container(param) {
  2.     function dec() {
  3.         if (secret > 0) {
  4.             secret -= 1;
  5.             return true;
  6.         } else {
  7.             return false;
  8.         }
  9.     }
  10.     this.member = param;
  11.     var secret = 3;
  12.     var that = this;
  13. }

私有方法 dec 檢查實例變量 secret 的值,如果它大於0就減少它的值然後返回true;否則它返回false。

它可以用於限制這個對象只能被使用3次。

根據協議,我們定義了一個私有變量that,用來讓私有方法可以訪問對象本身。

這是一個變通的解決方案,需要它的根本原因在於ECMAscrīpt語言規範的一個錯誤,而這個錯誤導致內部函數的this變量有

錯誤。(honker:似乎不用that也沒關係,也許是原文寫得太早了,哪位高人遇到過這種問題?)

私有方法不能被公開方法調用。爲了讓私有函數有用,我們需要引入特權方法的概念。


特權

特權方法可以訪問私有變量和方法,並且它本身可以被公開方法和外部訪問。可以刪除或替換一個特權方法但是不能改變它或強迫它放棄自己的祕密。

特權方法是在構造函數通過this定義的

  1. function Container(param) {
  2.     function dec() {
  3.         if (secret > 0) {
  4.             secret -= 1;
  5.             return true;
  6.         } else {
  7.             return false;
  8.         }
  9.     }
  10.     this.member = param;
  11.     var secret = 3;
  12.     var that = this;
  13.     this.service = function () {
  14.         if (dec()) {
  15.             return that.member;
  16.         } else {
  17.             return null;
  18.         }
  19.     };
  20. }

service是一個特權方法。前三次調用myContainer.service()將返回'abc',之後它將返回null。service調用私有的dec方法,dec方法訪問私有的secret變量。service對其他對象和函數都是可見的,但我們不能直接訪問private成員。


閉包

因爲有了閉包的我,這些公開、私有和特權方法的寫法才成爲可能。它意味着內部函數總能訪問它外層函數定義的變量和參數。即使外層函數已經返回。這是Javascrīpt的一個極其強大的特性。目前還沒有如何一本Javascrīpt編程的書講到如何利用它,大多都沒有提到它。

私有和特權成員只能在對象被構造時生成。公開成員可以在任何時間添加。


寫法

Public

  1. function Constructor(...) {
  2.     this.membername = value;
  3. }
  4. Constructor.prototype.membername = value;

Private

  1. function Constructor(...) {
  2.     var that = this;
  3.     var membername = value;
  4.     function membername(...) {...}
  5. }

Note: The function statement

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

is shorthand for

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

Privileged

  1. function Constructor(...) {
  2.     this.membername = function (...) {...};
  3. }
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章