Как мне объявить пространство имен в JavaScript? - PullRequest
954 голосов
/ 19 мая 2009

Как мне создать пространство имен в JavaScript, чтобы мои объекты и функции не перезаписывались другими объектами и функциями с тем же именем? Я использовал следующее:

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

Есть ли более элегантный или лаконичный способ сделать это?

Ответы [ 27 ]

1027 голосов
/ 10 мая 2011

Я использую подход, найденный на сайте Enterprise jQuery :

Вот их пример, показывающий, как объявлять частные и публичные свойства и функции. Все делается как самовыполняющаяся анонимная функция.

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

Так что, если вы хотите получить доступ к одному из публичных участников, вы просто должны пойти skillet.fry() или skillet.ingredients.

Что действительно здорово, так это то, что теперь вы можете расширять пространство имен, используя точно такой же синтаксис.

//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 ));

Третий undefined аргумент

Третий аргумент undefined является источником переменной со значением undefined. Я не уверен, что это все еще актуально сегодня, но, работая со старыми стандартами браузеров / JavaScript (ecmascript 5, javascript <1.8.5 ~ firefox 4), переменная global-scope <code>undefined доступна для записи, поэтому любой может переписать ее значение. Третий аргумент (если не передано значение) создает переменную с именем undefined, которая ограничена пространством имен / функцией. Поскольку при создании пространства имен не было передано никакого значения, по умолчанию используется значение undefined.

735 голосов
/ 19 мая 2009

Мне нравится это:

var yourNamespace = {

    foo: function() {
    },

    bar: function() {
    }
};

...

yourNamespace.foo();
336 голосов
/ 19 мая 2009

Еще один способ сделать это, который я считаю немного менее строгим, чем литеральная форма объекта, заключается в следующем:

var ns = new function() {

    var internalFunction = function() {

    };

    this.publicFunction = function() {

    };
};

Выше очень похоже на шаблон модуля и , нравится вам это или нет , оно позволяет вам выставлять все свои функции как общедоступные, избегая при этом жесткой структуры литерал объекта.

156 голосов
/ 26 мая 2010

Есть ли более элегантный или лаконичный способ сделать это?

Да. Например:

var your_namespace = your_namespace || {};

тогда вы можете иметь

var your_namespace = your_namespace || {};
your_namespace.Foo = {toAlert:'test'};
your_namespace.Bar = function(arg) 
{
    alert(arg);
};
with(your_namespace)
{
   Bar(Foo.toAlert);
}
90 голосов
/ 21 мая 2011

Я обычно строю это в замыкании:

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";
        }
    };
})();

Мой стиль с годами претерпел незначительные изменения с тех пор, как я написал это, и теперь я обнаружил, что пишу закрытие следующим образом:

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

Таким образом, я считаю, что общедоступный API и реализация проще для понимания. Думайте о выражении return как о публичном интерфейсе к реализации.

55 голосов
/ 09 ноября 2010

Поскольку вы можете писать разные файлы JavaScript, а затем объединять или не объединять их в приложении, каждый должен иметь возможность восстанавливать или создавать объект пространства имен без ущерба для работы других файлов ...

Один файл может использовать пространство имен namespace.namespace1:

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

namespace.namespace1.doSomeThing = function(){}

Другой файл может использовать пространство имен namespace.namespace2:

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

namespace.namespace2.doSomeThing = function(){}

Эти два файла могут жить вместе или независимо друг от друга.

47 голосов
/ 22 апреля 2012

Вот как Стоян Стефанов делает это в своей книге Patterns , которую я считаю очень хорошей (в ней также показано, как он делает комментарии, которые позволяют автоматически генерировать документацию API, и как добавить метод в прототип пользовательского объекта):

/**
* 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;
};
32 голосов
/ 28 августа 2010

Это продолжение ссылки user106826 на Namespace.js. Похоже, проект перешел на GitHub . Сейчас Смит / namespacedotjs .

Я использовал этот простой помощник JavaScript для своего крошечного проекта, и пока он кажется легким, но достаточно универсальным для обработки пространств имен и загрузки модулей / классов. Было бы замечательно, если бы это позволило мне импортировать пакет в пространство имен по своему выбору, не только в глобальное пространство имен ... вздох, но это не имеет значения.

Позволяет объявить пространство имен, а затем определить объекты / модули в этом пространстве имен:

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

Другой вариант - объявить пространство имен и его содержимое сразу:

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

Дополнительные примеры использования приведены в файле example.js в source .

32 голосов
/ 19 мая 2009

Я использую этот подход:

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

Внешний код может быть:

var myClass = new myNamespace.MyClass();
var myOtherClass = new myNamepace.subName.SomeOtherClass();
myNamespace.subName.publicOtherStuff(someParameter);
29 голосов
/ 10 мая 2012

Пример:

var namespace = {};
namespace.module1 = (function(){

    var self = {};
    self.initialized = false;

    self.init = function(){
        setTimeout(self.onTimeout, 1000)
    };

    self.onTimeout = function(){
        alert('onTimeout')
        self.initialized = true;
    };

    self.init(); /* If it needs to auto-initialize, */
    /* You can also call 'namespace.module1.init();' from outside the module. */
    return self;
})()

При желании вы можете объявить переменную local, same, например self, и назначить local.onTimeout, если хотите, чтобы она была закрытой.

...