Есть ли «краткий» способ сделать пространство имен в JavaScript?
Я часто встречал сайты, которые помещают весь свой JavaScript в namespace
структуру, подобную следующей:
namespaces = { com : { example: { example.com's data} }
Однако безопасная настройка по отношению к другим фреймворкам с пространством имен, по-видимому, требует относительно большого количества кода (определяемого как> 2 строк). Мне было интересно, знает ли кто-нибудь краткий способ сделать это? Кроме того, существует ли относительно стандартный / последовательный способ его структурирования? Например, com
присоединено ли пространство имен непосредственно к глобальному объекту или оно присоединено через объект пространства имен?
[Edit: упс, очевидно {com = { ... } }
, я не добился бы ничего близкого к тому, что я планировал, спасибо Shog9 за указание на это.]
Ответов (8)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() { /* ... */ }
};
})();
... что, ИМХО, достаточно лаконично.
Используйте литерал объекта и либо 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, "	");
/* Check type */
if (foo.hasOwnProperty("name"))
{
document.body.innerHTML += String("<pre>" + ["foo", String(foo.exec(foo)), foo.name] + "</pre>").replace(/,/g, "	");
}
/* 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, "	");
}
else
{
/* Fallback to atomic value */
counter = 0;
}
DOM использует следующее соглашение для определения интерфейсов HTML и SVG-элементов пространства имен:
- HTMLTitleElement
- SVGTitleElement
- SVGScriptElement
- HTMLScriptElement
Ядро JavaScript использует прототипы для создания пространства имен toString
метода как простой формы полиморфизма.
использованная литература
- Есть ли автобокс javascript?
- Получение одноуровневого значения ключа в литерале объекта JavaScript
- MDN: операторы JavaScript - это как объектный метод
- Lua: техническое примечание 7 - Модули и пакеты
- HTMLTitleElement.webidl
- SVGTitleElement.webidl
- SVGScriptElement.webidl
- HTMLScriptElement.webidl
- Названия функций в ES6
- Спецификация языка ECMAScript 2015 - 19.2.4.2 Экземпляры функций: name | ECMA-262 6-е издание
YUI библиотека библиотека содержит код , который обрабатывает пространства имен , используя функцию , которую вы можете найти предпочтительнее. Это могут делать и другие библиотеки.
Вот интересная статья Питера Мишо о пространстве имен Javascript . Он обсуждает 3 различных типа пространств имен Javascript:
- Префиксное пространство имен
- Пространство имен одного объекта
- Пространство имен вложенных объектов
Я не буду копировать то, что он здесь сказал, но я думаю, что его статья очень информативна.
Питер даже зашел так далеко, что указал на то, что некоторые из них имеют проблемы с производительностью. Я думаю, что эту тему было бы интересно обсудить, учитывая, что новые планы 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/>';