2011-08-21 92 views
17

我知道,這經常被討論。但是經過像19世紀以外的人一樣尋找,我需要一些建議。通過聲明一個「命名空間」我沒有問題,但是當談到prototype.foo函數時,我卡住了。我找到了一種方法,但我不喜歡它:使用函數原型的Javascript名稱空間聲明

Namespace = {} 
Namespace.obj = function() { 
    this.foo="bar"; 
} 
Namespace.obj.prototype.start = function() { 
    this.foo="fubar"; 
} 

blah = new Namespace.obj(); 
blah.start(); 

現在,因爲我在腳本的情況下有點神經質,我想有這樣的事情:

Namespace = { 
    obj: function() { 
     this.foo="bar"; 
    }, 
    obj.prototype.start: function(tabinst) { 
     this.foo="fubar"; 
    } 
} 
... 

但隨後會拋出一個錯誤: 「未捕獲的SyntaxError:意外的令牌。」

我知道,這是整容,但我認爲必須有更好的方法來聲明包含類和原型函數的「命名空間」。

回答

29

我會這樣做的方式是使用"Module pattern"
你基本上把你所有的「模塊」邏輯封裝在一個自動執行的函數中,它會返回一個包含你的類,函數,變量等的對象......想想你的模塊API的返回值。

Namespace = (function() { 
    /** Class obj **/ 
    var obj = function() { 
     this.foo = 'bar'; 
    }; 
    obj.prototype = { 
     start: function() { 
      this.foo = 'fubar'; 
     } 
    }; 

    /** Class obj2 **/ 
    var obj2 = function() { 
     this.bar = 'foo' 
    }; 
    obj2.prototype = { 
     start: function() { 
      this.bar = 'barfoo'; 
     }, 
     end: function() { 
      this.bar = ''; 
     } 
    }; 
    return { 
     obj : obj, 
     obj2: obj2 
    }; 
})(); 

var o = new Namespace.obj() 
o.start() 

爲了進一步封裝「目標文件」類的方法和構造函數,我們可以做到以下幾點:

/** Class obj **/ 
var obj = (function() { 
    /** class Constructor **/ 
    var obj = function() { 
     this.foo = 'bar'; 
    }; 
    /** class methods **/ 
    obj.prototype = { 
     start: function() { 
      this.foo = 'fubar'; 
     } 
    }; 
    return obj; 
})(); 

還有,採用這種模式來爲自由的一個重要特徵,這是「私人變量「,請考慮以下內容:

/** Class Foo **/ 
var Foo = (function() { 
    // Private variables 
    var private_number = 200 
    /** class Constructor **/ 
    var Foo = function() { 
     this.bar = 0; 
    }; 
    /** class methods **/ 
    Foo.prototype = { 
     add: function() { 
      this.bar += private_number; 
     } 
    }; 
    return Foo; 
})(); 

foo = new Foo(); 
alert(foo.bar); // 0 
foo.add(); 
alert(foo.bar);// 200 
alert(foo.private_number) //undefined 
+0

好方法,+1。 – Jiri

+0

Thans Amjad,這太好了。但是現在我又絆倒了。我看到它是正確的:使用這種方法不可能創建一個Namespace.blah()函數,它是從obj分離的? –

+2

@Johnny如果我理解你的問題,只需在返回對象中添加一個'blah'函數: '。 。 012hreturn { obj:obj, obj2:obj2, blah:function(){/ * do something * /} };' –

2

是因爲,你不能使用這種類型的對象聲明

obj.prototype或這裏obj.something鏈接的,因爲語言看到OBJ作爲非對象值。你可以僞造這樣一個像這樣

Namespace = {}; 

Namespace.obj =function() { 
     this.foo="bar"; 
}; 

Namespace.obj.prototype.start = function(tabinst) { 
     this.foo="fubar"; 
}; 

console.log(Namespace.obj.prototype); 

效果(見本小提琴http://jsfiddle.net/WewnF/

編輯:哇,我剛剛注意到,我說的已經是問題之內。我很抱歉沒有注意到這一點......那麼你描述自己的方式是實現這一目標的正確方法。

否則,您可以像這樣重新編寫代碼 - 但不完全符合您的要求,並且工作原理也不一樣(因爲obj本身不是函數,您必須調用它的主函數這樣obj.main();)

Namespace = { 
    obj: { 
      main : function() { 
       this.foo="bar"; 
      }, 
      prototype : { 
      start: function(tabinst) { 
      this.foo="fubar"; 
      } 
      } 
    } 
} 

編輯2:見本撥弄http://jsfiddle.net/NmA3v/1/

Namespace = { 
    obj: function() { 
     this.foo="bar"; 
    }, 
    prototype: { 
     obj : { 
      start : function(hi) { 
       alert(hi); 
      } 
     } 

    }, 

    initProto : function(){ 
     for(var key in Namespace) 
     { 
      if(key !== "prototype") 
      { 
       for(var jey in Namespace.prototype[ key ]) 
        Namespace[ key ].prototype[ jey ] = Namespace.prototype[ key ][ jey ]; 
      } 
     } 
    } 
} 

Namespace.initProto(); 

console.log(Namespace.obj); 

var test = new Namespace.obj(); 

test.start("Hello World"); 

這將有相同的效果。 說明:我們聲明我們的對象是正常的屬性函數,然後使用一個主對象,它具有與上面相同的名稱的對象,例如對於每個Namespace.obj,還有一個Namespace.prototype.obj,它包含我們想要在原型鏈中添加的功能。然後使用namespace.protoInit(),我們遍歷所有屬性 - 並從Namespace.prototype [key]中提取函數,並將它們添加到Namespace [key] .prototype - 成功擴展原型對象!有點非正統,但工作!

+0

編輯中的第一個片段不會按照您的想法工作。 'obj.main'和'obj.prototype'是兩個不同的獨立函數。是的,如果你不用'new'來調用它,而只是因爲它指向'window',那麼'this'將引用同一個對象。所以你會讓'foo'全球化。 –

+0

你的第二個例子將'Namespace'限制爲只包含一個「類」,它以某種方式破壞了命名空間的用途。 –

+0

對於第一個例子,你是正確的,我感到很蠢,因爲沒有注意到這一點,但我不同意第二個例子。爲什麼它只限於一個「班級」?如果您使用更多的對象,它將遍歷它們併爲它們分配正確的原型值。 – Pantelis

3

只是爲了踢和擴大上面的答案。基於嵌套名稱空間的更多對象符號定位

var NS = {}; 

// Class List 
NS.Classes = { 
    Shape: (function(){ 
    // Private 
    var whateveryouwishboss = false; 

    // Public 
    var Shape = function(x,y,w,h){ 
     this.x = x; 
     this.y = y; 
     this.w = w; 
     this.h = h; 
    }; 
    Shape.prototype = { 
     draw: function(){ 
     //... Im on prototype Shape 
     } 
    } 
    return Shape; 
    })(), 
    Person: (function(){ 
    //.... 
    })() 
} 

/////// Let the games begin 

var rect = new NS.Class.Shape(0,0,10,10); 
rect.draw()