2011-08-21 14 views
17

Lo so, questo è spesso discusso. Ma dopo aver cercato in giro come qualcuno del 19 ° secolo, ho bisogno di un consiglio. Non ho alcun problema dichiarando un "namespace", ma quando si tratta di una funzione prototype.foo, mi sono bloccato. Ho trovato un modo, ma non mi piace:Dichiarazione dello spazio dei nomi Javascript con funzione-prototipo

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

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

Ora, dato che sono un po 'nevrotica, in caso di scripting, mi piacerebbe avere qualcosa di simile:

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

Ma poi genera un errore: "Uncaught SyntaxError: Token inaspettato."

Lo so, questo è cosmetico, ma penso che ci debba essere un metodo migliore per dichiarare uno "spazio dei nomi" contenente una classe e funzioni di prototipo.

risposta

29

Il modo in cui lo farei è utilizzare lo "Module pattern".
Fondamentalmente si incapsula tutta la logica del "Modulo" in una funzione autoesposta che restituirebbe un oggetto con classi, funzioni, variabili, ecc ... Pensa al valore restituito come esposizione dell'API del modulo.

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() 

Al fine di incapsulare ulteriormente i metodi della classe "obj" e costruttore potremmo effettuare le seguenti operazioni:

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

C'è anche una caratteristica importante che viene fornito gratuitamente con questo modello, che è " Variabili private ", considerare quanto segue:

/** 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

Approccio gradevole, +1. – Jiri

+0

Than Amjad, è grandioso. Ma ora sto inciampando di nuovo. Lo vedo bene: con questo approccio non è possibile creare una funzione Namespace.blah() che è staccata forma obj? –

+2

@Johnny Se ho capito bene la tua domanda, aggiungi una funzione 'blah' all'oggetto restituito: '. . ritorno { obj: obj, obj2: obj2, bla: function() {/ * qualcosa da eseguire * /}} ; ' –

2

Sì, perché, non è possibile utilizzare questo tipo di concatenamento in una dichiarazione oggetto

obj.prototype o obj.something qui, perché il linguaggio vede obj come un valore non-oggetto. È possibile falso ad un effetto come questo

Namespace = {}; 

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

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

console.log(Namespace.obj.prototype); 

(si veda questo violino http://jsfiddle.net/WewnF/)

EDIT: Wow, ho appena notato che quello che ho detto era già all'interno della domanda. Mi dispiace tanto non averlo notato prima ... Beh, il modo in cui ti descrivi è il metodo corretto per raggiungere questo obiettivo.

Altrimenti puoi riscrivere il tuo codice in questo modo - ma non è esattamente quello che stai cercando e non funzionerà allo stesso modo (dato che obj non sarà una funzione in sé e dovrai chiamare la sua funzione principale come questo obj.main();)

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

EDIT 2: Vedere questo violino 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"); 

questo avrà lo stesso effetto esattamente. Spiegazione: stiamo dichiarando i nostri oggetti come normali proprietà-funzioni, e quindi usiamo un oggetto prototipo master che contiene oggetti con gli stessi nomi precedenti, ad esempio per ogni Namespace.obj, c'è anche un Namespace.prototype.obj che contiene le funzioni che vogliamo aggiungere nella catena del prototipo.

quindi con namespace.protoInit(), iteriamo attraverso tutte le proprietà - ed estraiamo le funzioni dalla Namespace.prototype [chiave] e le aggiungiamo a Namespace [chiave] .prototype - estendendo con successo l'oggetto prototipo! Un po 'non ortodosso, ma funziona!

+0

Il primo frammento nella modifica non funzionerà come si potrebbe pensare. 'obj.main' e' obj.prototype' sono due diverse funzioni indipendenti. Sì, 'this' si riferirà allo stesso oggetto se li chiami senza' new', ma solo perché si riferisce a 'window'. Quindi renderai 'foo' globale. –

+0

Il tuo secondo esempio limita 'Namespace' per contenere solo una" classe "che in qualche modo sconfigge lo scopo del namespace. –

+0

Sei corretto per il primo esempio e mi sento stupido per non averlo notato prima, ma non sono d'accordo sul secondo. Perché lo limita a una sola "classe"? Se si utilizzano più oggetti, verranno ripetuti e assegnati loro i valori prototipo corretti. – Pantelis

3

Solo per calci e per espandere la risposta sopra. Un po 'più di notazione orientata agli oggetti basata sullo spazio dei nomi nidificato

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() 
Problemi correlati