Pregunta ¿Cómo declaro un espacio de nombres en JavaScript?


¿Cómo creo un espacio de nombres en JavaScript para que mis objetos y funciones no sean sobrescritos por otros objetos y funciones con el mismo nombre? He usado lo siguiente:

if (Foo == null || typeof(Foo) != "object") { var Foo = new Object();}

¿Hay una manera más elegante o sucinta de hacer esto?


919
2018-05-19 08:11


origen


Respuestas:


Me gusta esto:

var yourNamespace = {

    foo: function() {
    },

    bar: function() {
    }
};

...

yourNamespace.foo();

713
2018-05-19 08:22



yo suelo el enfoque encontrado en el sitio Enterprise jQuery:

Aquí está su ejemplo que muestra cómo declarar propiedades y funciones privadas y públicas. Todo se hace como una función anónima autoejecutable.

(function( skillet, $, undefined ) {
    //Private Property
    var isHot = true;

    //Public Property
    skillet.ingredient = "Bacon Strips";

    //Public Method
    skillet.fry = function() {
        var oliveOil;

        addItem( "\t\n Butter \n\t" );
        addItem( oliveOil );
        console.log( "Frying " + skillet.ingredient );
    };

    //Private Method
    function addItem( item ) {
        if ( item !== undefined ) {
            console.log( "Adding " + $.trim(item) );
        }
    }
}( window.skillet = window.skillet || {}, jQuery ));

Entonces, si quieres acceder a uno de los miembros públicos, simplemente irás skillet.fry() o skillet.ingredients.

Lo que es realmente genial es que ahora puedes extender el espacio de nombres usando la misma sintaxis.

//Adding new Functionality to the skillet
(function( skillet, $, undefined ) {
    //Private Property
    var amountOfGrease = "1 Cup";

    //Public Method
    skillet.toString = function() {
        console.log( skillet.quantity + " " +
                     skillet.ingredient + " & " +
                     amountOfGrease + " of Grease" );
        console.log( isHot ? "Hot" : "Cold" );
    };
}( window.skillet = window.skillet || {}, jQuery ));

El tercero undefined argumento

El tercero, undefined argumento es la fuente de la variable de valor undefined. No estoy seguro de si todavía es relevante hoy, pero al trabajar con navegadores / estándares de JavaScript más antiguos (ecmascript 5, javascript <1.8.5 ~ firefox 4), la variable de alcance global undefined es grabable, por lo que cualquiera podría reescribir su valor. El tercer argumento (cuando no se pasa un valor) crea una variable llamada undefined que tiene un alcance para el espacio de nombres / función. Como no se pasó ningún valor cuando creó el espacio de nombre, se establece de manera predeterminada en el valor undefined.


1015
2018-05-10 08:28



Otra forma de hacerlo, que considero que es un poco menos restrictiva que la forma literal del objeto, es esta:

var ns = new function() {

    var internalFunction = function() {

    };

    this.publicFunction = function() {

    };
};

Lo anterior es más o menos como el patrón del módulo y te guste o no, le permite exponer todas sus funciones como públicas, mientras evita la estructura rígida de un objeto literal.


334
2018-05-19 08:39



¿Hay una manera más elegante o sucinta de hacer esto?

Sí. Por ejemplo:

var your_namespace = your_namespace || {};

entonces puedes tener

var your_namespace = your_namespace || {};
your_namespace.Foo = {toAlert:'test'};
your_namespace.Bar = function(arg) 
{
    alert(arg);
};
with(your_namespace)
{
   Bar(Foo.toAlert);
}

154
2018-05-26 11:34



Normalmente lo construyo en un cierre:

var MYNS = MYNS || {};

MYNS.subns = (function() {

    function privateMethod() {
        // Do private stuff, or build internal.
        return "Message";
    }

    return {
        someProperty: 'prop value',
        publicMethod: function() {
            return privateMethod() + " stuff";
        }
    };
})();

Mi estilo a lo largo de los años ha tenido un cambio sutil desde que escribí esto, y ahora me encuentro escribiendo el cierre de esta manera:

var MYNS = MYNS || {};

MYNS.subns = (function() {
    var internalState = "Message";

    var privateMethod = function() {
        // Do private stuff, or build internal.
        return internalState;
    };
    var publicMethod = function() {
        return privateMethod() + " stuff";
    };

    return {
        someProperty: 'prop value',
        publicMethod: publicMethod
    };
})();

De esta manera, encuentro que la API pública y la implementación son más fáciles de entender. Piense en la declaración de devolución como una interfaz pública para la implementación.


88
2018-05-20 20:07



Debido a que puede escribir diferentes archivos de JavaScript y luego combinarlos o no combinarlos en una aplicación, cada uno necesita poder recuperar o construir el objeto de espacio de nombres sin dañar el trabajo de otros archivos ...

Un archivo podría tener la intención de usar el espacio de nombres namespace.namespace1:

namespace = window.namespace || {};
namespace.namespace1 = namespace.namespace1 || {};

namespace.namespace1.doSomeThing = function(){}

Otro archivo puede querer usar el espacio de nombres namespace.namespace2:

namespace = window.namespace || {};
namespace.namespace2 = namespace.namespace2 || {};

namespace.namespace2.doSomeThing = function(){}

Estos dos archivos pueden vivir juntos o separados sin colisionar.


55
2017-11-09 04:27



Así es como Stoyan Stefanov lo hace en su Patrones de JavaScript libro que encontré muy bueno (también muestra cómo hace comentarios que permiten la documentación de la API generada automáticamente, y cómo agregar un método al prototipo de un objeto personalizado):

/**
* My JavaScript application
*
* @module myapp
*/

/** @namespace Namespace for MYAPP classes and functions. */
var MYAPP = MYAPP || {};

/**
* A maths utility
* @namespace MYAPP
* @class math_stuff
*/
MYAPP.math_stuff = {

    /**
    * Sums two numbers
    *
    * @method sum
    * @param {Number} a First number
    * @param {Number} b Second number
    * @return {Number} Sum of the inputs
    */
    sum: function (a, b) {
        return a + b;
    },

    /**
    * Multiplies two numbers
    *
    * @method multi
    * @param {Number} a First number
    * @param {Number} b Second number
    * @return {Number} The inputs multiplied
    */
    multi: function (a, b) {
        return a * b;
    }
};

/**
* Constructs Person objects
* @class Person
* @constructor
* @namespace MYAPP
* @param {String} First name
* @param {String} Last name
*/
MYAPP.Person = function (first, last) {

    /**
    * First name of the Person
    * @property first_name
    * @type String
    */
    this.first_name = first;

    /**
    * Last name of the Person
    * @property last_name
    * @type String
    */
    this.last_name = last;
};

/**
* Return Person's full name
*
* @method getName
* @return {String} First name + last name
*/
MYAPP.Person.prototype.getName = function () {
    return this.first_name + ' ' + this.last_name;
};

46
2018-04-22 15:44



Yo uso este enfoque:

var myNamespace = {}
myNamespace._construct = function()
{
    var staticVariable = "This is available to all functions created here"

    function MyClass()
    {
       // Depending on the class, we may build all the classes here
       this.publicMethod = function()
       {
          //Do stuff
       }
    }

    // Alternatively, we may use a prototype.
    MyClass.prototype.altPublicMethod = function()
    {
        //Do stuff
    }

    function privateStuff()
    {
    }

    function publicStuff()
    {
       // Code that may call other public and private functions
    }

    // List of things to place publically
    this.publicStuff = publicStuff
    this.MyClass = MyClass
}
myNamespace._construct()

// The following may or may not be in another file
myNamespace.subName = {}
myNamespace.subName._construct = function()
{
   // Build namespace
}
myNamespace.subName._construct()

El código externo puede ser:

var myClass = new myNamespace.MyClass();
var myOtherClass = new myNamepace.subName.SomeOtherClass();
myNamespace.subName.publicOtherStuff(someParameter);

32
2018-05-19 08:26



Esta es una continuación del enlace de user106826 a Namespace.js. Parece que el proyecto se movió a GitHub. Esto es ahora smith / namespacedotjs.

He estado usando este sencillo asistente de JavaScript para mi pequeño proyecto y hasta ahora parece ser lo suficientemente ligero y versátil como para manejar el espacio de nombres. y cargar módulos / clases. Sería genial si me permitiera importar un paquete en un espacio de nombre de mi elección, no solo el espacio de nombres global ... suspiro, pero eso es además del punto.

Le permite declarar el espacio de nombre y luego definir objetos / módulos en ese espacio de nombres:

Namespace('my.awesome.package');
my.awesome.package.WildClass = {};

Otra opción es declarar el espacio de nombre y su contenido a la vez:

Namespace('my.awesome.package', {
    SuperDuperClass: {
        saveTheDay: function() {
            alert('You are welcome.');
        }
    }
});

Para obtener más ejemplos de uso, consulte el archivo example.js en la fuente.


32
2017-08-27 23:15