2009-11-30 96 views
10

我對JS比較陌生,我遇到了正確模擬OOP原則的問題。JavaScript類和可變範圍

我想我有兩個問題。質疑第一個是關於許多方法來聲明變量。

說我有一個類:

function clazz(a) 
{ 
    this.b = 2; 
    var c = 3; 
    this.prototype.d = 4; // or clazz.prototype.d = 4? 
} 

var myClazz = new clazz(1); 

我是正確的以下評估:

一個是私有變量,例如特定的(即不同clazz中的情況下,將具有獨特的變量和自變量'一個')。它可以從clazz內部訪問爲:'a'。

b是一個實例特定的公共變量。它可以從clazz內部作爲'this.b'和外部clazz作爲'myClazz.b'訪問。

c是一個靜態或類特定的私有變量(即不同的clazz實例將共享相同的'c'變量)。它可以在clazz的任何實例中作爲'c'訪問,clazz實例中的變化反映在所有clazz實例中。

d是一個靜態/類特定的公共變量。它可以通過'clazz.prototype.d'或'myClazz.prototype.d'從任何地方訪問。

整體的問題,我有我的變量方案的理解是,有沒有辦法來聲明一個私有變量不是靜態的(即獨特的換版之類的每個實例)。

第二個問題是針對不同類型的聲明。

我一直在使用:

var MySingleton = new function() {...}; 

創建單身。它是否正確?我也不能確定爲在這種情況下,「新」的關鍵字的效果以及追加()函數括號來聲明的結尾像這樣:

var MySingleton = new function() {...}(); 

我一直在使用這個模式聲明一個類然後實例化該類的實例:

function myClass() {...}; 
var classA = new myClass(); 
var classB = new myClass(); 

這是正確的方法嗎?

回答

18

你爲ab是正確的:

a一種說法,只有constructor function的範圍內使用。

b是一個公共實例變量,可用於使用該構造函數創建的所有實例。

c是一個私有變量,只能在構造函數中訪問。

d聲明是無效的,因爲prototype對象是指只能使用於constructor functions,像Clazz.prototype.d = 3;,如果你像這樣做,變量會被共享的,但你可以在一個特定的實例分配一個值,並且默認值將爲被遮蔽(通過原型鏈)。

對於「私有變量」你可以用你聲明c的方式,例如:

function Clazz(){ 
    var c = 3; // private variable 

    this.privilegedMethod = function() { 
     alert(c); 
    }; 
} 

特權方法,是公開的,但他們可以訪問的構造函數內聲明的「私有」變量。

爲了創建單身,最簡單的方法也許是使用對象文本,如:

var myInstance = { 
    method1: function() { 
    // ... 
    }, 
    method2: function() { 
    // ... 
    } 
}; 

如果你想在你的單一實例私有成員,您可以:

var myInstance = (function() { 
    var privateVar = ''; 

    function privateMethod() { 
    // ... 
    } 

    return { // public interface 
    publicMethod1: function() { 
     // all private members are accesible here 
    }, 
    publicMethod2: function() { 
    } 
    }; 
})(); 

這被稱爲模塊模式,它基本上允許你通過利用closures的優勢將私有成員封裝在一個對象上。

更多信息:

編輯:關於語法,後:

var mySingleton = new (function() { 
    // ... 
})(); 

通過使用new運營商,你是十二月使用一步一個「匿名構造函數」,這將生成一個新的對象實例,它是有效的,但我個人更喜歡「模塊」模式的方法,創建我自己的對象實例(並避免new )。

另外,讀new function() {},我認爲這不是很直觀,可能會造成混淆,如果你不明白new運營商如何工作。

關於括號,它們是可選的,該new運營商將調用無參數的構造函數,如果你不加入他們(ECMA-262,11.2.2)。

+2

+1。一個非常完整和信息豐富的答案。 – 2009-11-30 23:51:17

+0

謝謝您提供的信息。 後續工作:單件聲明的模塊方法和原始文章中引用的樣式之間的有形差異是什麼? – Cmc 2009-12-01 15:41:03

+0

** @ Lior:**謝謝!,** Cmc:**我寫了一些關於你發佈的語法...... – CMS 2009-12-01 17:06:59

3

OK,讓我們去在這個:

  1. 「一」是傳遞給你的類的構造函數的參數。它只會在構造函數調用期間存在。這意味着你應該在某處存儲它的值。

  2. 'b'是一個公共實例成員。它是特定於實例的(同樣,因爲您在構造函數中賦值,所有實例最初將具有相同的'b'值)。

  3. 'c'是一個私人實例成員。但是,它只能在構造函數內部訪問,因爲它只在該範圍內定義。除非你從你的構造函數中的閉包來引用它,否則它的命運將與上面的'a'類似。

  4. 'd'是一個公共實例成員。您的班級的每個實例最初都會有一個值爲4的成員「d」。但是請注意,將引用類型對象分配給類的原型成員(如'd')將使每個實例成員'd'引用同一個對象。例如:

    MyClass.prototype.d = { prop1: 'val1', prop2: 'val2' };   
    var a = new MyClass(); 
    var b = new MyClass();   
    a.d.prop1 = 'foo'; // is the same as: b.d.prop1 = 'foo'; 
    
  5. 類的靜態成員使用定義:

    function MyClass() 
    { 
        // ... 
    }  
    MyClass.staticMemeber = 'I am a static member'; 
    

    你可能不應該把MyClass.prototype以保持分配給你的類的靜態成員/ methods.Everything的地方'原型反過來是它的每個實例的成員。

  6. 當()被附加到函數定義(正好在塊之後)時,函數被執行。這意味着:

    var myFunc = function() { alert('blah'); }(); 
    

    只會導致方法調用。以下代碼:

    var MySingleton = new function() {...}(); 
    

    意味着'使用function()的返回值作爲MySingleton的構造函數「。