Existe uma maneira “concisa” de fazer namespace em JavaScript?
-
08-06-2019 - |
Pergunta
Tenho encontrado frequentemente sites que colocam todo o seu JavaScript dentro de um namespace
estrutura nos moldes de:
namespaces = { com : { example: { example.com's data} }
No entanto, configurar isso com segurança em relação a outras estruturas com namespace parece exigir uma quantidade relativamente grande de código (definida como> 2 linhas).Eu queria saber se alguém conhece uma maneira concisa de fazer isso?Além disso, existe uma maneira relativamente padrão/consistente de estruturá-lo?Por exemplo, é o com
namespace diretamente anexado ao objeto global ou é anexado por meio de um objeto de namespace?
[Editar:opa, obviamente {com = { ... } }
não conseguiria nada próximo do que pretendi, obrigado ao Shog9 por apontar isso.]
Solução
Javascript não possui namespaces independentes.Possui funções, que podem fornecer escopo para resolução de nomes, e objetos, que podem contribuir para que os dados nomeados sejam acessíveis em um determinado escopo.
Aqui está o seu exemplo, corrigido:
var namespaces = { com: { example: { /* example.com's data */ } } }
Esta é uma variável namespaces
sendo atribuído um objeto literal.O objeto contém uma propriedade: com
, um objeto com uma propriedade: example
, um objeto que provavelmente conteria algo interessante.
Então, você pode digitar algo como namespaces.com.exemplo.somePropertyOrFunctionOnExample e tudo vai funcionar.Claro, também é ridículo.Você não tem um namespace hierárquico, você tem um objeto contendo um objeto contendo um objeto com as coisas que realmente lhe interessam.
var com_example_data = { /* example.com's data */ };
Isso funciona igualmente bem, sem a hierarquia inútil.
Agora, se você realmente querer para construir uma hierarquia, você pode tentar algo assim:
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() { /* ... */ }
};
})();
... o que é, IMHO, razoavelmente conciso.
Outras dicas
Aqui estava um artigo interessante de Peter Michaux sobre Namespace Javascript.Ele discute três tipos diferentes de namespace Javascript:
- Namespace de prefixo
- Namespace de objeto único
- Namespace de objetos aninhados
Não vou plagiar o que ele disse aqui, mas acho que seu artigo é muito informativo.
Peter chegou ao ponto de apontar que há considerações de desempenho em alguns deles.Acho que seria interessante falar sobre este tópico, considerando que os novos planos do ECMAScript Harmony abandonaram os planos 4.0 para namespace e empacotamento.
Tento seguir a convenção do Yahoo de criar um único objeto pai no escopo global para conter tudo;
var FP = {};
FP.module = {};
FP.module.property = 'foo';
Para ter certeza de não substituir um objeto existente, você deve fazer algo como:
if(!window.NameSpace) {
NameSpace = {};
}
ou
var NameSpace = window.NameSpace || {};
Dessa forma, você pode colocar isso no topo de cada arquivo em seu aplicativo/site sem se preocupar em sobrescrever o objeto namespace.Além disso, isso permitiria escrever testes de unidade para cada arquivo individualmente.
O Biblioteca YUI biblioteca possui código que lida com namespace usando uma função que você pode achar preferível.Outras bibliotecas também podem fazer isso.
Como alternativa a um ponto ou sublinhado, você pode usar o cifrão:
var namespaces$com$example = "data";
Eu também gosto disso (fonte):
(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/>';
Use um objeto literal e o this
objeto ou o nome explícito para fazer o namespace com base nas propriedades irmãs da variável local que contém a função.Por exemplo:
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());
Ou sem o explícito name
propriedade:
var foo = { bar: function rodimus(){return this; } }
var baz = { bar: function optimus(){return this; } }
console.log(foo.bar.name);
console.log(baz.bar.name);
Ou sem usar 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);
Use o RegExp
ou Object
funções construtoras para adicionar propriedades de nome a variáveis de contador e outros nomes comuns e, em seguida, use um hasOwnProperty
teste para fazer a verificação:
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;
}
O DOM usa a seguinte convenção para definir namespaces de interface de elementos HTML e SVG:
- HTMLTitleElement
- Elemento SVGTitle
- Elemento SVGScript
- Elemento HTMLScript
O núcleo do JavaScript usa protótipos para criar o namespace do toString
método como uma forma simples de polimorfismo.
Referências
- O javascript faz caixa automática?
- Obtendo o valor irmão da chave em um literal de objeto JavaScript
- MDN:Operadores JavaScript - isto como um método de objeto
- Lua:nota técnica 7 – Módulos e Pacotes
- HTMLTitleElement.webidl
- SVGTitleElement.webidl
- SVGScriptElement.webidl
- HTMLScriptElement.webidl
- Os nomes das funções no ES6
- Especificação de linguagem ECMAScript 2015 - 19.2.4.2 Instâncias de função:nome | ECMA-262 6ª Edição