2010-08-05 16 views
15

Quiero crear un espacio de nombres global para mi aplicación y en ese espacio de nombres quiero otros espacios de nombres:JavaScript Namespace

E.g.

Dashboard.Ajax.Post() 

Dashboard.RetrieveContent.RefreshSalespersonPerformanceContent(); 

también quiero colocarlos en archivos separados:

  • ajax.js
  • RetrieveContent.js

Sin embargo, he intentado usar this método, sin embargo, ganó' t funciona porque el mismo nombre de variable se usa para el espacio de nombres en 2 lugares separados. ¿Alguien puede ofrecer una alternativa?

Gracias.

+0

Nombre del espacio de nombres algo diferente? –

+0

Supongo que es una opción, sin embargo, esperaba incluir todo en un espacio de nombres, ya que pensé que sería más ordenado de esa manera. –

Respuesta

1

Se podría hacer algo como esto ...

página HTML usando la biblioteca de espacio de nombres:

<html> 
<head> 
    <title>javascript namespacing</title> 
    <script src="dashboard.js" type="text/javascript"></script> 
    <script src="ajax.js" type="text/javascript"></script> 
    <script src="retrieve_content.js" type="text/javascript"></script> 
    <script type="text/javascript"> 
     alert(Dashboard.Ajax.Post()); 
     alert(Dashboard.RetrieveContent.RefreshSalespersonPerformanceContent()); 
     Dashboard.RetrieveContent.Settings.Timeout = 1500; 
     alert(Dashboard.RetrieveContent.Settings.Timeout); 
    </script> 
</head> 

<body> 
    whatever... 
</body> 

</html> 

Dashboard.js:

(function(window, undefined){ 
    var dashboard = {}; 
    window.Dashboard = dashboard; 
})(window); 

ajax.js:

(function(){ 
    var ajax = {}; 
    ajax.Post = function() { return "Posted!" }; 
    window.Dashboard.Ajax = ajax 
})(); 

Retrieve_Content.js:

(function(){ 
    var retrieveContent = {}; 
    retrieveContent.RefreshSalespersonPerformanceContent = function() { 
     return "content retrieved" 
    }; 


    var _contentType; 
    var _timeout; 
    retrieveContent.Settings = { 
     "ContentType": function(contentType) { _contentType = contentType; }, 
     "ContentType": function() { return _contentType; }, 
     "Timeout": function(timeout) { _timeout = timeout; }, 
     "Timeout": function() { return _timeout; } 
    }; 

    window.Dashboard.RetrieveContent = retrieveContent; 

})(); 

El Dashboard.js actúa como el punto de partida para todos los espacios de nombres debajo de ella. El resto se define en sus respectivos archivos. En Retrieve_Content.js, agregué algunas propiedades adicionales allí bajo Settings para dar una idea de cómo hacer eso, si es necesario.

+0

No obstante, no se garantiza que 'retrieve_content.js' se cargue y analice después de' Dashboard.js'. Si alguna de las bibliotecas dependientes se carga antes de que se cargue 'Dashboard.js', las asignaciones fallarán. –

+1

En general, 'Dashboard.js' se cargará y analizará primero, pero eso no está garantizado. El objeto 'Dashboard' se pudo verificar antes de la asignación y se creó si fuera necesario, pero eso requeriría algún código duplicado en' retrieve_content.js' y 'ajax.js'. El requisito de archivos separados del PO me condujo a lo anterior. – ironsam

4

La función Yahoo Namespace está diseñada exactamente para este problema.

Agregado:

El source de la función está disponible. Puede copiarlo en su propio código si lo desea, cambiar la raíz de YAHOO a otra cosa, etc.

9

Solo necesita asegurarse de no pisar su objeto de espacio de nombres si ya se ha creado. Algo como esto funcionaría:

(function() { 
    // private vars can go in here 


    Dashboard = Dashboard || {}; 
    Dashboard.Ajax = { 
     Post: function() { 
      ... 
     } 
    }; 
})(); 

y el archivo RetrieveContent se definen de manera similar.

+0

Hola, estoy tratando de poner mi código en espacios de nombres también, pero tengo una pregunta: Tengo muchos archivos de JavaScript, en caso de que agregue 'Dashboard = Dashboard || {}; '(si ese fuera mi espacio de nombres) en cada archivo? Y segundo, ¿tengo que prefijar cada variable a Dashboard.x en lugar de x o no es necesario porque todo vive en el mismo espacio de nombres? – Michel

3

Existen varias bibliotecas que ya ofrecen este tipo de funcionalidad si desea utilizar o examinar una solución precocida (es decir, una prueba).

El uno libre de errores más simple y más para ponerse en marcha con jQuery.extend es, probablemente, la el argumento deep establecido en verdadero. (La razón por la que digo que está libre de errores no es porque creo que jQuery.extend adolece de menos errores que cualquiera de las otras bibliotecas, sino porque ofrece una opción clara para copiar los atributos desde el remitente al receptor, que la mayoría de las otras bibliotecas explícitamente no proporcionan. Esto evitará que muchos errores difíciles de diagnosticar aparezcan en su programa más tarde porque utilizó una copia superficial extend y ahora tiene funciones que se ejecutan en contextos que no esperaba que fueran ejecutando in. (Sin embargo, si es consciente de cómo va a ampliar su biblioteca base mientras diseña sus métodos, esto no debería ser un problema.)

1

Creo que el patrón del módulo podría estar en su calle. Aquí hay una buena artículo sobre diferentes patrones de módulos.

http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth

+0

Las respuestas con solo enlaces no son tan útiles. Debería haber suficiente explicación aquí. La pregunta es cómo definir objetos en espacios de nombres de dos ubicaciones diferentes –

+1

@JuanMendes: el artículo explica exactamente eso. Varias de las mejores respuestas son básicamente solo enlaces. Además, esto fue hace más de un año y medio. –

+0

Nunca encontré el patrón de módulo apropiado para el espacio de nombres. Un espacio de nombre no es un bloque de código "reutilizable" (aunque pueden ser piezas individuales de NS). Los literales de objetos siempre han funcionado lo suficientemente bien para mí. – 1nfiniti

3

Con el objeto creado NS, sólo debe ser capaz de añadir a la misma desde donde quiera. Aunque es posible que desee probar var NS = NS || {}; para asegurarse de que el objeto NS existe y no se sobrescribe.

// NS is a global variable for a namespace for the app's code 
var NS = NS || {}; 

NS.Obj = (function() { 

    // Private vars and methods always available to returned object via closure 
    var foo; // ... 

    // Methods in here are public 
    return { 
    method: function() { 

    } 
    }; 

}()); 
1

le recomiendo que utilice esta técnica:

https://github.com/mckoss/namespace

namespace.lookup('com.mydomain.mymodule').define(function (ns) { 
    var external = namespace.lookup('com.domain.external-module'); 

    function myFunction() { 
    ... 
    } 

    ... 

    ns.extend({ 
    'myFunction': myFunction, 
    ... 
    }); 
}); 

He estado usando este patrón durante un par de años; Desearía que más bibliotecas hicieran lo mismo; También me ha resultado mucho más fácil compartir código en mis diferentes proyectos.

7

Here es un artículo muy bueno sobre varios "Patrones de módulos" en JavaScript. Hay una pequeña sección muy agradable sobre cómo puede aumentar módulos o espacios de nombres y mantener un estado privado entre archivos. Es decir, el código en archivos separados se ejecutará secuencialmente y aumentará adecuadamente el espacio de nombres después de que se ejecute.

No he explorado esta técnica a fondo así que no hay promesas ... pero aquí está la idea básica.

dashboard.js

(function(window){ 

    var dashboard = (function() { 
     var my = {}, 
      privateVariable = 1; 

     function privateMethod() { 
      // ... 
     } 

     my.moduleProperty = 1; 
     my.moduleMethod = function() { 
      // ... 
     }; 

     return my; 
    }()); 

    window.Dashboard = dashboard; 
})(window); 

dashboard.ajax.js

var dashboard = (function (my) { 
    var _private = my._private = my._private || {}, 
     _seal = my._seal = my._seal || function() { 
      delete my._private; 
      delete my._seal; 
      delete my._unseal; 
     }, 
     _unseal = my._unseal = my._unseal || function() { 
      my._private = _private; 
      my._seal = _seal; 
      my._unseal = _unseal; 
     }; 

    // permanent access to _private, _seal, and _unseal 

    my.ajax = function(){ 
     // ... 
    } 

    return my; 
}(dashboard || {})); 

dashboard.retrieveContent.js

var dashboard = (function (my) { 
    var _private = my._private = my._private || {}, 
     _seal = my._seal = my._seal || function() { 
      delete my._private; 
      delete my._seal; 
      delete my._unseal; 
     }, 
     _unseal = my._unseal = my._unseal || function() { 
      my._private = _private; 
      my._seal = _seal; 
      my._unseal = _unseal; 
     }; 

    // permanent access to _private, _seal, and _unseal 

    my.retrieveContent = function(){ 
     // ... 
    } 

    return my; 
}(dashboard || {})); 
+0

¿Podría explicarme cómo esto permite acceder a las variables privadas que se declararon en otro archivo? Más específico si tuviera que llamar a dashboard._seal(), ¿cómo dashboard._unseal() me permite acceder a la privacidad nuevamente? –

0

bob.js puede ayudar a la hora de definir los espacios de nombres (entre otros):

bob.ns.setNs('Dashboard.Ajax', { 

    Post: function() { /*...*/ } 
}); 

bob.ns.setNs('Dashboard.RetrieveContent', { 

    RefreshSalespersonPerformanceContent: function() { /*...*/ } 
}); 
1

he escrito esta función para simplificar la creación de espacios de nombres. Mabey te ayudará.

function ns(nsstr) { 
    var t = nsstr.split('.'); 
    var obj = window[t[0]] = window[t[0]] || {}; 
    for (var i = 1; i < t.length; i++) { 
     obj[t[i]] = obj[t[i]] || {}; 
     obj = obj[t[i]]; 
    } 
} 

ns('mynamespace.isawesome.andgreat.andstuff'); 
mynamespace.isawesome.andgreat.andstuff = 3; 

console.log(mynamespace.isawesome.andgreat.andstuff); 
0

Implementación:

namespace = function(packageName) 
{ 
    // Local variables. 
    var layers, layer, currentLayer, i; 

    // Split the given string into an array. 
    // Each element represents a namespace layer. 
    layers = packageName.split('.'); 

    // If the top layer does not exist in the global namespace. 
    if (eval("typeof " + layers[0]) === 'undefined') 
    { 
     // Define the top layer in the global namesapce. 
     eval(layers[0] + " = {};"); 
    } 

    // Assign the top layer to 'currentLayer'. 
    eval("currentLayer = " + layers[0] + ";"); 

    for (i = 1; i < layers.length; ++i) 
    { 
     // A layer name. 
     layer = layers[i]; 

     // If the layer does not exist under the current layer. 
     if (!(layer in currentLayer)) 
     { 
      // Add the layer under the current layer. 
      currentLayer[layer] = {}; 
     } 

     // Down to the next layer. 
     currentLayer = currentLayer[layer]; 
    } 

    // Return the hash object that represents the last layer. 
    return currentLayer; 
}; 


Resultado:

namespace('Dashboard.Ajax').Post = function() { 
    ...... 
}; 

namespace('Dashboard.RetrieveContent').RefreshSalespersonPerformanceContent = function() { 
    ...... 
}; 


Gi ST:

namespace.js