2010-05-25 31 views
1

最近我看到了下面的代碼創建一個JavaScript類:問題關於JavaScript類定義的特定模式

var Model.Foo = function(){ 
    // private stuff 
    var a, b; 

    // public properties 
    this.attr1 = ''; 
    this.attr2 = ''; 

    if(typeof Model.Foo._init === 'undefined'){ 
    Model.Foo.prototype = { 
     func1 : function(){ //...}, 
     func2 : function(){ //... }, 
     //other prototype functions 
    } 
    } 
    Model.Foo._init = true; 
} 

// Instantiate and use the class as follows: 
var foo = new Model.Foo(); foo.func1(); 

我猜_init變量用來確保我們不會再次定義原型。另外,我感覺代碼更具可讀性,因爲我將所有內容都放在一個功能塊中(所以在oop-speak中,所有的屬性和方法都在一個地方)。 您是否看到上述代碼的任何問題?如果我需要在大型項目中創建大量類,那麼使用這種模式會有什麼缺陷?

回答

1

它似乎不必要的複雜。您需要遵守原則,以便在原型擴展的實現中不使用Model.Foo的任何參數或局部變量。奇怪的是覆蓋整個.prototype對象,而不僅僅是添加單個成員。爲什麼不以正常的方式來做到這一點?

var Model.Foo = function(){ 
    // private stuff 
    var a, b; 

    // public properties 
    this.attr1 = ''; 
    this.attr2 = ''; 
} 

Model.Foo.prototype.func1 = function(){ //...}; 
Model.Foo.prototype.func2 = function(){ //... }; 

備用允許每個實例的成員變量私人

var Model.Foo = function(){ 
    // private stuff 
    var a, b; 

    // public properties 
    this.attr1 = ''; 
    this.attr2 = ''; 

    this.func1 = function(){ //...}; 
    this.func2 = function(){ //... }; 
} 
+0

所以,我認爲在原型函數中使用私有屬性會更簡單(帶閉包)。你會如何建議使用私人atuff?在類函數裏面有'this.func(){alert(a);}'這個東西嗎?爲什麼你不會在原型函數中使用私有屬性? – fenderplayer 2010-05-25 22:20:53

+0

我不會在原型方法中使用私有屬性或參數給構造函數,因爲它們對於正在創建的實例是特殊的,而原型方法將應用於所有實例。然後,對Model.Foo()的第一次調用會產生一些獨特的效果,似乎很難維護。 – 2010-05-25 22:39:18

+0

使用Javascript,我並不真正隱藏私處。我忘記了將原型成員推出功能塊,不允許私有變量。我決定我可以忍受這一點。如果你不能忍受這一點,你必須把這些功能放在構造函數中。但是不要像原來那樣將它們附加到原型上,因爲那些私有變量不再是每個實例的變量,而是跨實例共享。 – 2010-05-25 22:42:15

2

這是一個奇怪的Javascript模式,我永遠不會用它來開發面向對象的JS代碼。一方面,Model.Foo._init === 'undefined'永遠不會評估到true如果Model.Foo._init是什麼,但字符串'undefined';因此,代碼

Model.Foo.prototype = { 
    func1 : function(){ /* ... */}, 
    func2 : function(){ /* ... */}, 
    //other prototype functions 
} 

將不會運行,除非該條件成立。 (也許作者是想添加一個typeof,如typeof Model.Foo._init === 'undefined'?我不知道)

爲了解決你對「確保我們不再定義原型」的擔憂,這已經實現了:

Model.Foo = function() { 
    // private stuff 
    var a, b; 

    // public properties 
    this.attr1 = ''; 
    this.attr2 = ''; 
}; 

Model.Foo.prototype = { 
    func1 : function() { /* ... */}, 
    func2 : function() { /* ... */} 
    //,other prototype functions 
}; 

// Instantiate and use the class as follows: 
var foo = new Model.Foo(); 
foo.func1(); 

這是沿着我建議,如果你不使用框架的路線。

基本上,你的問題的答案是:如果你使用這種非標準模式進行開發,那麼其他程序員,甚至幾個月後你甚至可能會發現很難擴展和使用。

+0

是的,你說得對,它的typeof ....我的壞 – fenderplayer 2010-05-25 21:58:52

+0

,如果你想使用一些私人的東西,在一個原型功能是什麼? – fenderplayer 2010-05-25 22:28:17

+0

如果你想要一個'func'來警示'a'的值,那麼你可以使用類似http://pastebin.com/wSff15cH的東西。注意第6行將'this.func'(而不是'Model.Foo.prototype.func')設置爲一個函數對象。如示例所示,公共屬性也可以是方法。但是,請記住,對於所有'Model.Foo'實例,'func'的定義不再是相同的'Function'對象。此外,所有局部變量的值以及構造函數的參數都不會GC'd。因此,如果你在你的代碼中使用了很多'Model.Foo'的實例,那麼你將會使用大量的內存。 – 2010-05-26 10:52:25

0

有幾件事情脫穎而出,成爲潛在的麻煩:

  1. Foo.prototype被設置爲一個簡單的對象,使用這種模式不能擴展任何東西。
  2. 「私人東西」在哪裏使用?每次創建新對象時,都會創建新的專用變量,這些變量似乎只能用於Foo.prototype中定義的函數,該函數只能運行一次。

這是一個混亂,並有詳細資料/例子遍佈網絡更好的是做到這一點。

0

下面的例子說明了我個人隨時間開發的圖案。

它利用範圍允許私人領域和方法。

詳細討論,請看看JavaScript class patterns

Employee = (function(){ 

    // private static field 
    var staticVar; 

    // class function a.k.a. constructor 
    function cls() 
    { 
    // private instance field 
    var name = ""; 
    var self = this; 

    // public instance field 
    this.age = 10; 

    // private instance method 
    function increment() 
    { 
     // must use self instead of this 
     self.age ++; 
    } 

    // public instance method 
    this.getName = function(){ 
     return cls.capitalize(name); 
    }; 

    this.setName = function(name2){ 
     name = name2; 
    }; 

    this.increment = function(){ 
     increment(); 
    }; 

    this.getAge = function(){ 
     return this.age; 
    }; 
    } 

    // public static field 
    cls.staticVar = 0; 

    // public static method 
    cls.capitalize = function(name){ 
     return name.substring(0, 1).toUpperCase() + 
      name.substring(1).toLowerCase(); 
    }; 

    // private static method 
    function createWithName(name) 
    { 
    var obj = new cls(); 
    obj.setName(cls.capitalize(name)); 
    return obj; 
    } 

    return cls; 
})(); 

john = new Employee(); 
john.setName("john"); 

mary = new Employee(); 
mary.setName("mary"); 
mary.increment(); 

alert("John's name: " + john.getName() + ", age==10: "+john.getAge()); 
alert("Mary's name: " + mary.getName() + ", age==11: "+mary.getAge());