Como eu declaro um namespace em JavaScript?

Como eu crio um namespace em JavaScript para que meus objects e funções não sejam sobrescritos por outros objects e funções com o mesmo nome? Eu usei o seguinte:

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

Existe uma maneira mais elegante ou sucinta de fazer isso?

Eu gosto disso:

 var yourNamespace = { foo: function() { }, bar: function() { } }; ... yourNamespace.foo(); 

Eu uso a abordagem encontrada no site da empresa jQuery :

Aqui está o exemplo deles mostrando como declarar propriedades e funções privadas e públicas. Tudo é feito como uma function anônima auto-executável.

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

Então, se você quiser acessar um dos membros públicos, basta acessar skillet.fry() ou skillet.ingredients .

O que é realmente legal é que agora você pode estender o namespace usando exatamente a mesma syntax.

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

O terceiro argumento undefined

O terceiro argumento undefined é a fonte da variável de valor undefined . Não tenho certeza se ainda é relevante hoje, mas ao trabalhar com navegadores mais antigos / padrões JavaScript (ecmascript 5, javascript <1.8.5 ~ firefox 4), a variável global-scope undefined é gravável, portanto qualquer um poderia rewrite seu valor. O terceiro argumento (quando não é passado um valor) cria uma variável denominada undefined que tem escopo para o namespace / function. Como nenhum valor foi passado quando você criou o namespace, o valor padrão é undefined .

Outra maneira de fazer isso, que eu considero um pouco menos restritiva que a forma literal do object, é esta:

 var ns = new function() { var internalFunction = function() { }; this.publicFunction = function() { }; }; 

O acima é muito parecido com o padrão de módulo e, quer você goste ou não , ele permite que você exponha todas as suas funções como públicas, evitando a estrutura rígida de um literal de object.

Existe uma maneira mais elegante ou sucinta de fazer isso?

Sim. Por exemplo:

 var your_namespace = your_namespace || {}; 

então você pode ter

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

Eu normalmente construo em um fechamento:

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

Meu estilo ao longo dos anos teve uma mudança sutil desde que escrevi isso, e agora me vejo escrevendo o fechamento assim:

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

Dessa forma, acho que a API pública e a implementação são mais fáceis de entender. Pense na declaração de retorno como sendo uma interface pública para a implementação.

Como você pode escrever arquivos diferentes de JavaScript e depois combinar ou não combiná-los em um aplicativo, cada um precisa ser capaz de recuperar ou construir o object de namespace sem danificar o trabalho de outros arquivos …

Um arquivo pode pretender usar o namespace namespace.namespace1 :

 namespace = window.namespace || {}; namespace.namespace1 = namespace.namespace1 || {}; namespace.namespace1.doSomeThing = function(){} 

Outro arquivo pode querer usar o namespace namespace.namespace2 :

 namespace = window.namespace || {}; namespace.namespace2 = namespace.namespace2 || {}; namespace.namespace2.doSomeThing = function(){} 

Esses dois arquivos podem viver juntos ou separados sem colidir.

Veja como Stoyan Stefanov faz isso em seu livro JavaScript Patterns , que eu achei muito bom (ele também mostra como ele faz comentários que permitem a documentação da API gerada automaticamente e como adicionar um método ao protótipo de um object personalizado):

 /** * My JavaScript application * * @module myapp */ /** @namespace Namespace for MYAPP classs 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; }; 

Eu uso essa abordagem:

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

Código externo pode então ser:

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

Esta é uma continuação do link de user106826 para Namespace.js. Parece que o projeto foi movido para o GitHub . Agora é smith / namespacedotjs .

Eu tenho usado esse simples auxiliar de JavaScript para meu minúsculo projeto e até agora parece ser leve, mas versátil o suficiente para lidar com namespacing e carregar módulos / classs. Seria ótimo se me permitisse importar um pacote para um namespace de minha escolha, não apenas o namespace global … suspiro, mas isso é além do ponto.

Ele permite que você declare o namespace e defina objects / módulos nesse namespace:

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

Outra opção é declarar o namespace e seu conteúdo de uma só vez:

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

Para mais exemplos de uso, veja o arquivo example.js na origem .

Amostra:

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

Opcionalmente, você pode declarar uma variável local , same self same e atribuir local.onTimeout se quiser que ela seja privada.

Você pode declarar uma function simples para fornecer namespaces.

 function namespace(namespace) { var object = this, tokens = namespace.split("."), token; while (tokens.length > 0) { token = tokens.shift(); if (typeof object[token] === "undefined") { object[token] = {}; } object = object[token]; } return object; } // Usage example namespace("foo.bar").baz = "I'm a value!"; 

Eu criei namespace que é inspirado nos módulos de Erlang. É uma abordagem muito funcional, mas é assim que escrevo meu código JavaScript hoje em dia.

Ele fornece um fechamento para um espaço de nomes global e expõe funções de um conjunto definido dentro desse fechamento.

 (function(){ namespace("images", previous, next); // ^^ This creates or finds a root object, images, and binds the two functions to it. // It works even though those functions are not yet defined. function previous(){ ... } function next(){ ... } function find(){ ... } // A private function })(); 

Se você precisar do escopo particular:

 var yourNamespace = (function() { //Private property var publicScope = {}; //Private property var privateProperty = "aaa"; //Public property publicScope.publicProperty = "bbb"; //Public method publicScope.publicMethod = function() { this.privateMethod(); }; //Private method function privateMethod() { console.log(this.privateProperty); } //Return only the public parts return publicScope; }()); yourNamespace.publicMethod(); 

mais, se você nunca vai usar o escopo privado:

 var yourNamespace = {}; yourNamespace.publicMethod = function() { // Do something... }; yourNamespace.publicMethod2 = function() { // Do something... }; yourNamespace.publicMethod(); 

Eu uso a seguinte syntax para o namespace.

 var MYNamespace = MYNamespace|| {}; MYNamespace.MyFirstClass = function (val) { this.value = val; this.getValue = function(){ return this.value; }; } var myFirstInstance = new MYNamespace.MyFirstClass(46); alert(myFirstInstance.getValue()); 

jsfiddle: http://jsfiddle.net/rpaul/4dngxwb3/1/

Depois de portar várias de minhas bibliotecas para diferentes projetos, e ter que constantemente estar mudando o namespace de nível superior (nomeado estaticamente), mudei para usar essa pequena function auxiliar (de código aberto) para definir namespaces.

 global_namespace.Define('startpad.base', function(ns) { var Other = ns.Import('startpad.other'); .... }); 

Descrição dos benefícios estão no meu post no blog . Você pode pegar o código fonte aqui .

Um dos benefícios que realmente gosto é o isolamento entre os módulos em relação à ordem de carga. Você pode consultar um módulo externo ANTES de ser carregado. E a referência do object obtida será preenchida quando o código estiver disponível.

Estou 7 anos atrasado para a festa, mas trabalhei um pouco com isso oito anos atrás:

É importante poder criar com facilidade e eficiência vários namespaces nesteds para manter um aplicativo da Web complexo organizado e gerenciável, respeitando o namespace global do JavaScript (evitando a poluição do namespace) e sem danificar os objects existentes no caminho do namespace .

Do acima exposto, esta foi a minha solução de cerca de 2008:

 var namespace = function(name, separator, container){ var ns = name.split(separator || '.'), o = container || window, i, len; for(i = 0, len = ns.length; i < len; i++){ o = o[ns[i]] = o[ns[i]] || {}; } return o; }; 

Isso não está criando um namespace, mas fornece uma function para criar namespaces.

Isso pode ser condensado em um one-liner minificado:

 var namespace=function(c,f,b){var e=c.split(f||"."),g=b||window,d,a;for(d=0,a=e.length;d 

Exemplo de uso:

 namespace("com.example.namespace"); com.example.namespace.test = function(){ alert("In namespaced function."); }; 

Ou, como uma declaração:

 namespace("com.example.namespace").test = function(){ alert("In namespaced function."); }; 

Ou então é executado como:

 com.example.namespace.test(); 

Se você não precisa de suporte para navegadores herdados, uma versão atualizada:

 const namespace = function(name, separator, container){ var o = container || window; name.split(separator || '.').forEach(function(x){ o = o[x] = o[x] || {}; }); return o; }; 

Agora, eu estaria desconfiado de expor o namespace para o namespace global em si. (Pena que o idioma base não forneça isso para nós!) Então eu normalmente usaria isso em um fechamento, como:

 (function(){ const namespace = function(name, separator, container){ var o = container || window; name.split(separator || '.').forEach(function(x){ o = o[x] = o[x] || {}; }); return o; }; const ns = namespace("com.ziesemer.myApp"); // Optional: ns.namespace = ns; // Further extend, work with ns from here... }()); console.log("\"com\":", com); 

O padrão do módulo foi originalmente definido como uma maneira de fornecer encapsulamento privado e público para classs na engenharia de software convencional.

Ao trabalhar com o padrão do módulo, podemos achar útil definir um modelo simples que usamos para começar a usá-lo. Aqui está uma que abrange variables ​​de espaçamento de nomes, públicas e privadas.

Em JavaScript, o padrão Module é usado para emular ainda mais o conceito de classs de forma que possamos include methods e variables ​​públicos / privados dentro de um único object, protegendo assim partes específicas do escopo global. O que isso resulta é uma redução na probabilidade de nossos nomes de funções conflitarem com outras funções definidas em scripts adicionais na página.

 var myNamespace = (function () { var myPrivateVar, myPrivateMethod; // A private counter variable myPrivateVar = 0; // A private function which logs any arguments myPrivateMethod = function( foo ) { console.log( foo ); }; return { // A public variable myPublicVar: "foo", // A public function utilizing privates myPublicFunction: function( bar ) { // Increment our private counter myPrivateVar++; // Call our private method using bar myPrivateMethod( bar ); } }; })(); 

Vantagens

Por que o padrão do módulo é uma boa escolha? Para começar, é muito mais limpo para os desenvolvedores que vêm de um contexto orientado a objects do que a ideia de encapsulamento verdadeiro, pelo menos do ponto de vista do JavaScript.

Em segundo lugar, ele suporta dados privados – assim, no padrão do Módulo, partes públicas de nosso código são capazes de tocar as partes íntimas, no entanto, o mundo externo é incapaz de tocar as partes privadas da class.

Desvantagens

As desvantagens do padrão do Módulo são que, à medida que acessamos membros públicos e privados de maneira diferente, quando desejamos alterar a visibilidade, na verdade, precisamos fazer alterações em cada local em que o membro foi usado.

Nós também não podemos acessar membros privados em methods que são adicionados ao object em um momento posterior . Dito isso, em muitos casos, o padrão do Módulo ainda é bastante útil e, quando usado corretamente, certamente tem o potencial de melhorar a estrutura de nossa aplicação.

O padrão do módulo de revelação

Agora que estamos um pouco mais familiarizados com o padrão de módulo, vamos dar uma olhada em uma versão ligeiramente melhorada – o padrão de Revelação do Christian Heilmann.

O padrão do Módulo Revelador surgiu porque Heilmann estava frustrado com o fato de ter que repetir o nome do object principal quando quiséssemos chamar um método público de outro ou acessar variables ​​públicas. Ele também não gostava da exigência do padrão do Módulo para ter que alternar para objetar a notação literal das coisas que ele queria tornar públicas.

O resultado de seus esforços foi um padrão atualizado em que simplesmente definiríamos todas as nossas funções e variables ​​no escopo particular e retornaria um object anônimo com pointers para a funcionalidade privada que gostaríamos de revelar como pública.

Um exemplo de como usar o padrão Revealing Module pode ser encontrado abaixo

 var myRevealingModule = (function () { var privateVar = "Ben Cherry", publicVar = "Hey there!"; function privateFunction() { console.log( "Name:" + privateVar ); } function publicSetName( strName ) { privateVar = strName; } function publicGetName() { privateFunction(); } // Reveal public pointers to // private functions and properties return { setName: publicSetName, greeting: publicVar, getName: publicGetName }; })(); myRevealingModule.setName( "Paul Kinlan" ); 

Vantagens

Esse padrão permite que a syntax de nossos scripts seja mais consistente. Também deixa mais claro no final do módulo quais de nossas funções e variables ​​podem ser acessadas publicamente, o que facilita a legibilidade.

Desvantagens

Uma desvantagem desse padrão é que, se uma function privada se referir a uma function pública, essa function pública não poderá ser substituída se uma correção for necessária. Isso ocorre porque a function privada continuará a se referir à implementação privada e o padrão não se aplica a membros públicos, apenas a funções.

Os membros de objects públicos que se referem a variables ​​privadas também estão sujeitos às notas de regra sem patch acima.

Você tem que verificar Namespace.js !

Meu padrão favorito tornou-se ultimamente isso:

 var namespace = (function() { // expose to public return { a: internalA, c: internalC } // all private /** * Full JSDoc */ function internalA() { // ... } /** * Full JSDoc */ function internalB() { // ... } /** * Full JSDoc */ function internalC() { // ... } /** * Full JSDoc */ function internalD() { // ... } })(); 

Eu gosto da solução do Jaco Pretorius, mas eu queria tornar a palavra-chave “this” um pouco mais útil apontando para o object module / namespace. Minha versão da skillet:

 (function ($, undefined) { console.log(this); }).call(window.myNamespace = window.myNamespace || {}, jQuery); 

Bastante um follow-up da resposta de Ionuț G. Stan, mas mostrando os benefícios do código organizado usando var ClassFirst = this.ClassFirst = function() {...} , que tira proveito do escopo de fechamento do JavaScript para menos confusão de namespace para classs no mesmo namespace.

 var Namespace = new function() { var ClassFirst = this.ClassFirst = function() { this.abc = 123; } var ClassSecond = this.ClassSecond = function() { console.log("Cluttered way to access another class in namespace: ", new Namespace.ClassFirst().abc); console.log("Nicer way to access a class in same namespace: ", new ClassFirst().abc); } } var Namespace2 = new function() { var ClassFirst = this.ClassFirst = function() { this.abc = 666; } var ClassSecond = this.ClassSecond = function() { console.log("Cluttered way to access another class in namespace: ", new Namespace2.ClassFirst().abc); console.log("Nicer way to access a class in same namespace: ", new ClassFirst().abc); } } new Namespace.ClassSecond() new Namespace2.ClassSecond() 

Saída:

 Cluttered way to access another class in namespace: 123 Nicer way to access a class in same namespace: 123 Cluttered way to access another class in namespace: 666 Nicer way to access a class in same namespace: 666 

We can use it independently in this way:

 var A = A|| {}; AB = {}; AB = { itemOne: null, itemTwo: null, }; ABitemOne = function () { //.. } ABitemTwo = function () { //.. } 

I think you all use too much code for such a simple problem. No need to make a repo for that. Here’s a single line function.

 namespace => namespace.split(".").reduce((last, next) => (last[next] = (last[next] || {})), window); 

Try it :

 // --- definition --- const namespace = namespace => namespace.split(".").reduce((last, next) => (last[next] = (last[next] || {})), window); // --- Use ---- let myNamespace = namespace("abc"); myNamespace.MyClass = class MyClass {}; // --- see ---- console.log("a : ", a); 

If using a Makefile you can do this.

 // prelude.hjs billy = new ( function moduleWrapper () { const exports = this; // postlude.hjs return exports; })(); // someinternalfile.js function bob () { console.log('hi'); } exports.bob = bob; // clientfile.js billy.bob(); 

I prefer to use a Makefile anyway once I get to about 1000 lines because I can effectively comment out large swaths of code by removing a single line in the makefile. It makes it easy to fiddle with stuff. Also, with this technique the namespace only appears once in the prelude so it’s easy to change and you don’t have to keep repeating it inside the library code.

A shell script for live development in the browser when using a makefile:

 while (true); do make; sleep 1; done 

Add this as a make task ‘go’ and you can ‘make go’ to keep your build updated as you code.

I’ve written another namespacing library that works a bit more like packages / units do in other languages. It allows you to create a package of JavaScript code and the reference that package from other code:

File hello.js

 Package("hello", [], function() { function greeting() { alert("Hello World!"); } // Expose function greeting to other packages Export("greeting", greeting); }); 

File Example.js

 Package("example", ["hello"], function(greeting) { // Greeting is available here greeting(); // Alerts: "Hello World!" }); 

Only the second file needs to be included in the page. Its dependencies (file hello.js in this example) will automatically be loaded and the objects exported from those dependencies will be used to populate the arguments of the callback function.

You can find the related project in Packages JS .

My habit is to use function myName() as property storage, and then var myName as “method” holder…

Whether this is legitimate enough or not, beat me! I am relying on my PHP logic all the time, and things simply work. : D

 function myObj() { this.prop1 = 1; this.prop2 = 2; this.prop3 = 'string'; } var myObj = ( (myObj instanceof Function !== false) ? Object.create({ $props: new myObj(), fName1: function() { /* code.. */ }, fName2: function() { /* code ...*/ } }) : console.log('Object creation failed!') ); 

if (this !== that) myObj.fName1(); else myObj.fName2();

You can also do it in a ‘vice versa’ way to check before object creation which is much better :

 function myObj() { this.prop1 = 1; this.prop2 = 2; this.prop3 = 'string'; } var myObj = ( (typeof(myObj) !== "function" || myObj instanceof Function === false) ? new Boolean() : Object.create({ $props: new myObj(), init: function () { return; }, fName1: function() { /* code.. */ }, fName2: function() { /* code ...*/ } }) ); if (myObj instanceof Boolean) { Object.freeze(myObj); console.log('myObj failed!'); debugger; } else myObj.init(); 

Reference to this: JavaScript: Creating Object with Object.create()

In JavaScript there are no predefined methods to use namespaces. In JavaScript we have to create our own methods to define NameSpaces. Here is a procedure we follow in Oodles technologies.

Register a NameSpace Following is the function to register a name space

 //Register NameSpaces Function function registerNS(args){ var nameSpaceParts = args.split("."); var root = window; for(var i=0; i < nameSpaceParts.length; i++) { if(typeof root[nameSpaceParts[i]] == "undefined") root[nameSpaceParts[i]] = new Object(); root = root[nameSpaceParts[i]]; } } 

To register a Namespace just call the above function with the argument as name space separated by '.' (ponto). For Example Let your application name is oodles. You can make a namespace by following method

 registerNS("oodles.HomeUtilities"); registerNS("oodles.GlobalUtilities"); var $OHU = oodles.HomeUtilities; var $OGU = oodles.GlobalUtilities; 

Basically it will create your NameSpaces structure like below in backend:

 var oodles = { "HomeUtilities": {}, "GlobalUtilities": {} }; 

In the above function you have register a namespace called "oodles.HomeUtilities" and "oodles.GlobalUtilities" . To call these namespaces we make an variable ie var $OHU and var $OGU .

These variables are nothing but an alias to Intializing the namespace. Now, Whenever you declare a function that belong to HomeUtilities you will declare it like following:

 $OHU.initialization = function(){ //Your Code Here }; 

Above is the function name initialization and it is put into an namespace $OHU . and to call this function anywhere in the script files. Just use following code.

 $OHU.initialization(); 

Similarly, with the another NameSpaces.

Espero que ajude.