Есть ли «краткий» способ сделать пространство имен в JavaScript?

Я часто встречал сайты, которые помещают весь свой JavaScript в namespace структуру, подобную следующей:

namespaces = { com : { example: { example.com's data} }

Однако безопасная настройка по отношению к другим фреймворкам с пространством имен, по-видимому, требует относительно большого количества кода (определяемого как> 2 строк). Мне было интересно, знает ли кто-нибудь краткий способ сделать это? Кроме того, существует ли относительно стандартный / последовательный способ его структурирования? Например, com присоединено ли пространство имен непосредственно к глобальному объекту или оно присоединено через объект пространства имен?

[Edit: упс, очевидно {com = { ... } }, я не добился бы ничего близкого к тому, что я планировал, спасибо Shog9 за указание на это.]

Ответов (8)

Решение

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

Вот ваш пример, исправленный:

var namespaces = { com: { example: { /* example.com's data */ } } }

Это переменная, namespaces которой назначается литерал объекта. Объект содержит одно свойство:, com объект с одним свойством:, example объект, который предположительно может содержать что-то интересное.

Итак, вы можете ввести что-то вроде namespaces.com.example. somePropertyOrFunctionOnExample, и все будет работать. Конечно, это тоже смешно. У вас нет иерархического пространства имен, у вас есть объект, содержащий объект, содержащий то, что вам действительно важно.

var com_example_data = { /* example.com's data */ };

Это так же хорошо работает без бессмысленной иерархии.

Теперь , если вы действительно хотите построить иерархию, вы можете попробовать что-то вроде этого:

com_example = com_example || {};
com_example.flags = com_example.flags || { active: false, restricted: true};

com_example.ops = com_example.ops || (function()
    {
       var launchCodes = "38925491753824"; // hidden / private
       return {
         activate: function() { /* ... */ },
         destroyTheWorld: function() { /* ... */ }
       };
    })();

... что, ИМХО, достаточно лаконично.

Я стараюсь следовать соглашению Yahoo о создании единственного родительского объекта в глобальной области видимости, содержащего все;

var FP = {};
FP.module = {};
FP.module.property = 'foo';

В качестве альтернативы точке или подчеркиванию вы можете использовать знак доллара:

var namespaces$com$example = "data"; 

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

var foo = { bar: function(){return this.name; }, name: "rodimus" }
var baz = { bar: function(){return this.name; }, name: "optimus" }

console.log(foo.bar());
console.log(baz.bar());

Или без явного name свойства:

var foo = { bar: function rodimus(){return this; } }
var baz = { bar: function optimus(){return this; } }

console.log(foo.bar.name);
console.log(baz.bar.name);

Или без использования this :

var foo = { bar: function rodimus(){return rodimus; } }
var baz = { bar: function optimus(){return optimus; } }

console.log(foo.bar.name);
console.log(baz.bar.name);

Используйте функции конструктора RegExp или, Object чтобы добавить свойства имени к переменным счетчика и другим общим именам, а затем используйте hasOwnProperty тест для проверки:

 var foo = RegExp(/bar/);
 
/* Add property */
foo.name = "alpha";

document.body.innerHTML = String("<pre>" + ["name", "value", "namespace"] + "</pre>").replace(/,/g, "&#09;");

/* Check type */
if (foo.hasOwnProperty("name")) 
  {
  document.body.innerHTML += String("<pre>" + ["foo", String(foo.exec(foo)), foo.name] + "</pre>").replace(/,/g, "&#09;");
  }

/* Fallback to atomic value */
else 
  {
  foo = "baz";
  }

var counter = Object(1);

/* Add property */
counter.name = "beta";

if (counter.hasOwnProperty("name")) 
  {
  document.body.innerHTML += String("<pre>" + ["counter", Number(counter), counter.name] + "</pre>").replace(/,/g, "&#09;");
  } 
else 
  {
  /* Fallback to atomic value */
  counter = 0;
  }

DOM использует следующее соглашение для определения интерфейсов HTML и SVG-элементов пространства имен:

  • HTMLTitleElement
  • SVGTitleElement
  • SVGScriptElement
  • HTMLScriptElement

Ядро JavaScript использует прототипы для создания пространства имен toString метода как простой формы полиморфизма.

использованная литература

YUI библиотека библиотека содержит код , который обрабатывает пространства имен , используя функцию , которую вы можете найти предпочтительнее. Это могут делать и другие библиотеки.

Вот интересная статья Питера Мишо о пространстве имен Javascript . Он обсуждает 3 различных типа пространств имен Javascript:

  1. Префиксное пространство имен
  2. Пространство имен одного объекта
  3. Пространство имен вложенных объектов

Я не буду копировать то, что он здесь сказал, но я думаю, что его статья очень информативна.

Питер даже зашел так далеко, что указал на то, что некоторые из них имеют проблемы с производительностью. Я думаю, что эту тему было бы интересно обсудить, учитывая, что новые планы ECMAScript Harmony отказались от планов 4.0 в отношении размещения имен и упаковки.

Чтобы убедиться, что вы не перезаписываете существующий объект, вы должны сделать что-то вроде:

if(!window.NameSpace) {
    NameSpace = {};
}

или

var NameSpace = window.NameSpace || {};

Таким образом, вы можете поместить это в начало каждого файла в вашем приложении / веб-сайте, не беспокоясь о перезаписи объекта пространства имен. Кроме того, это позволит вам писать модульные тесты для каждого файла индивидуально.

Мне также нравится это ( источник ):

(function() {
    var a = 'Invisible outside of anonymous function';
    function invisibleOutside() {
    }

    function visibleOutside() {
    }
    window.visibleOutside = visibleOutside;

    var html = '--INSIDE Anonymous--';
    html += '<br/> typeof invisibleOutside: ' + typeof invisibleOutside;
    html += '<br/> typeof visibleOutside: ' + typeof visibleOutside;
    contentDiv.innerHTML = html + '<br/><br/>';
})();

var html = '--OUTSIDE Anonymous--';
html += '<br/> typeof invisibleOutside: ' + typeof invisibleOutside;
html += '<br/> typeof visibleOutside: ' + typeof visibleOutside;
contentDiv.innerHTML += html + '<br/>';​