Continuando a postagem anterior JavaScript IIFE como contêiner de códigos, compartilhamos aqui mais um artigo do blog Desenvolvimento Para Web. A equipe da Turbosite repassa seu conhecimento sobre JavaScript Module Pattern (Padrão de Módulo), um padrão de desenvolvimento bastante comum para Javascript. As próximas linhas abaixo abrangem deste o estudo básico ao avançado desse padrão.
Anonymous Closures são o construto fundamental em Module Pattern que tornam tudo isso possível e são uma das melhores característica de JavaScript: é possível criar uma função anônima e executá-la imediatamente. Todo o código que é executado dentro da função esta no escopo do closure (algo como “fechamento”), o que proporciona privacidade e estado durante toda a vida da aplicação.
(function () {
// Todas variáveis e funções estão somente neste escopo
// e ainda mantêm acesso a todos os globais
}()); Observe a () em torno da função anônima. Isto é requerido pela linguagem, uma vez que declarações que começam com a função de token são sempre considerados declarações de função. Incluir () cria uma expressão de função.
JavaScript tem um recurso conhecido como implied globals (globals implícitas). Sempre que um nome é usado, o interpretador volta pela cadeia de escopo em busca de uma declaração de variável (var) para esse nome. Se nada for encontrado, a variável é assumida como global; se é usado em um assignmente, o global é criado se não existir. Isso significa que o uso ou a criação de variáveis globais em um closure anônimo é fácil. Infelizmente, isso leva a código difícil de gerir, já que não é óbvio (para humanos) que as variáveis são globais em um determinado arquivo.
Felizmente, o recurso de função anônima fornece uma alternativa fácil a isso. Ao passar globais como parâmetros para a função anônima, que os importa para o código. Eis um exemplo:
(function ($, YAHOO) {
// Agora se tem acesso às globais jQuery (como "$") e YAHOO nesse código
}(jQuery, YAHOO));
Às vezes, você não quer apenas usar globais, mas quer declará-los. É possível fazer isso facilmente ao exportá-los, usando o valor de retorno da função anônima. Se o fizer, completará o Padrão de Módulo básico. Veja um exemplo completo:
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}()); Observe que foi declarado um módulo global chamado MODULE com duas propriedades públicas: um método chamado MODULE.moduleMethod e uma variável chamada MODULE.moduleProperty. Além disso, ele mantém o estado interno privada usando o closure da função anônima — e também é possível importar globais necessários usando o padrão mostrado anteriormente.
Uma limitação do Module Pattern até agora é que o módulo inteiro deve estar em um arquivo. Quem já trabalhou em uma grande base de código entende o valor de divisão de código em vários arquivos. Felizmente, existe uma boa solução: Augmentation (Ampliação). Em primeiro lugar, é preciso importar o módulo; então, são adicionadas novas propriedades e; por fim, ele é exportado.
Aqui está um exemplo de uso de Augmentation:
var MODULE = (function (my) {
my.anotherMethod = function () {
// Método adicionado...
};
return my;
}(MODULE)); É usada a palavra-chave var novamente para consistência, apesar de não ser estritamente necessário. Após este código ser executado, o módulo terá ganho um novo método público chamado MODULE.anotherMethod. Este arquivo “ampliado” também manterá seu próprio estado interno privado e importações.
Enquanto o exemplo acima requer a criação inicial do módulo em primeiro lugar e a ampliação acontecer depois disso, isso nem sempre é necessário. Uma das melhores coisas que um aplicativo JavaScript pode fazer em relação a desempenho é carregar scripts de forma assíncrona. É possível criar módulos flexíveis de várias partes que podem se carregar em qualquer ordem com o Loose Augmentation (Ampliação Fraca). Cada arquivo deve ter a seguinte estrutura:
var MODULE = (function (my) {
// Adiciona recursos...
return my;
}(MODULE || {})); Neste padrão, a instrução var é sempre necessária. Note que a importação vai criar o módulo se ele ainda não existir. Isto significa que você pode usar uma ferramenta como LABjs e carregar todos os seus arquivos de módulo em paralelo, sem a necessidade de bloquear.
Tight Augmentation (Ampliação Forte) é excelente, mas coloca algumas limitações no módulo, dentre as quais se destaca a impossibilidade de poder substituir as propriedades do módulo de maneira segura. Também não é possível usar as propriedades do módulo de outros arquivos durante a inicialização — embora seja possível em tempo de execução após a inicialização. Loose Augmentation implica numa ordem estabelecida de carregamento, mas permite substituições.
Eis um exemplo simples (ampliando o módulo-exemplo original):
var MODULE = (function (my) {
var old_moduleMethod = my.moduleMethod;
my.moduleMethod = function () {
// sobrescrita de método com acesso ao antigo através de old_moduleMethod foi
};
return my;
}(MODULE)); MODULE.moduleMethod foi substituído, mas manteve uma referência para o método original, caso fosse necessário.
Dentre os Padrões de Module Pattern, talvez este seja a opção mais flexível. Ele permite que algumas composições elegantes, mas que vem à custa da flexibilidade: propriedades que são objetos ou funções não serão duplicadas e existirão como um objeto com duas referências. Mudando uma, mudará a outra. Isso pode ser corrigido para objetos com um processo de clonagem recursiva, mas, provavelmente, não pode ser fixado para funções — exceto, talvez, com eval().
var MODULE_TWO = (function (old) {
var my = {},
key;
for (key in old) {
if (old.hasOwnProperty(key)) {
my[key] = old[key];
}
}
var super_moduleMethod = old.moduleMethod;
my.moduleMethod = function () {
// sobrescreve método ao clonar, acesso ao super através de super_moduleMethod
};
return my;
}(MODULE));
Uma limitação grave de dividir um módulo em vários arquivos é que cada arquivo mantém seu próprio estado privado e não tem acesso ao estado privado dos outros arquivos. Mas isso pode ser corrigido. Aqui está um exemplo de um módulo com Ampliação Fraca que vai manter o estado privado em todos as ampliações:
var MODULE = (function (my) {
var _private = my._private = my._private || {},
_seal = my._seal = my._seal || function () {
delete my._private;
delete my._seal;
delete my._unseal;
},
_unseal = my._unseal = my._unseal || function () {
my._private = _private;
my._seal = _seal;
my._unseal = _unseal;
};
// Acesso permanente a _private, _seal e _unseal
return my;
}(MODULE || {})); Qualquer arquivo pode definir propriedades em sua variável local _private e esta será imediatamente disponível para os outros. Uma vez que este módulo foi completamente carregado, o aplicativo deve chamar MODULE._seal(), que irá impedir o acesso externo ao interno _private.
Se este módulo fosse ampliado novamente, mais à frente na vida aplicativo um dos métodos internos, em qualquer arquivo, pode chamar _unseal() antes de carregar o novo arquivo e _seal() novamente depois de ter sido executado.
O padrão de Module Pattern Submódulo (Sub-module) é considerado pela maioria como o mais simples. Há muitos bons casos para a criação de submódulos. É como criar módulos regulares:
MODULE.sub = (function () {
var my = {};
// ...
return my;
}()); Embora isso possa parecer bastante óbvio, vale a pena ser mencionado em um artigo desse tipo, haja vista que submódulos têm todas as capacidades avançadas de módulos normais, incluindo ampliação e estado privado.
A maioria dos Padrões Avançados de Module Pattern podem ser combinados uns com os outros para criar padrões mais úteis. Não raramente é possível encontrar, em aplicações mais complexas, a combinação de Ampliação Fraca, Estado Privado e Submódulos.
No decorrer do artigo, não se mencionou a respeito de performance, mas uma nota rápida sobre isso seria: Module Pattern é bom para performance! Ele passa por minificação muito bem, o que faz com que o download seja mais rápido. Usar Loose Augmentation permite downloads paralelos, fáceis e sem bloqueios. O tempo de inicialização é, provavelmente, um pouco mais lento do que outros métodos, mas o custo-benefício vale a pena. Desempenho em tempo de execução não deve sofrer penalidades desde que globais sejam importados corretamente e, provavelmente, há aumento de velocidade em submódulos, encurtando a cadeia de referência com variáveis locais.
Para fechar sobre Module Patterns, aqui está um exemplo de um submódulo que se carrega dinamicamente a seu parent (criando-se se ele não existe) — o estado privado foi deixado de fora para que o exemplo fique mais conciso, mas incluir isso seria simples.
var UTIL = (function (parent, $) {
var my = parent.ajax = parent.ajax || {};
my.get = function (url, params, callback) {
// Um pouquinho de trapaça... xD
return $.getJSON(url, params, callback);
};
// etc
return parent;
}(UTIL || {}, jQuery)); Este padrão de código permite que toda uma base de códigos complexa hierárquica seja completamente carregada em paralelo, com sub-módulos e tudo o mais.
Boas-vindas ao WordPress. Esse é o seu primeiro post. Edite-o ou exclua-o, e então comece…
Forneça Serviços Melhores Com Informações de Localização Precisas Ofereça aos usuários as mesmas experiências de…
Sabemos que aumentar as vendas é a chave para o sucesso de qualquer negócio. Mas…
Sabemos que aumentar as vendas é a chave para o sucesso de qualquer negócio. Mas…
QRCode significa Reposta Rápida e surgiu como uma evolução dos antigos códigos de barras. Hoje…
Se você administra um negócio pessoal, familiar ou trabalha para uma grande empresa, aumentar as…