A programação modular é um padrão de programação JavaScript muito comum. Geralmente, pode facilitar o entendimento do código, mas existem muitas práticas excelentes que não são bem conhecidas.
Base
Vamos primeiro descrever brevemente alguns padrões modulares desde que Eric Miraglia (o desenvolvedor de Yui) publicou pela primeira vez um blog há três anos descrevendo padrões modulares. Se você já estiver muito familiarizado com esses modos modulares, pode pular esta seção diretamente e começar a ler do "Modo Avançado".
Fechamento anônimo
Esta é uma estrutura básica que torna tudo possível e também é a melhor característica do JavaScript. Vamos simplesmente criar uma função anônima e executá -la imediatamente. Todo o código será executado nessa função e viverá em um fechamento que fornece privatização, o que é suficiente para permitir as variáveis nesses fechamentos para percorrer toda a vida de nossa aplicação.
A cópia do código é a seguinte:
(function () {
// ... todos os vars e funções estão apenas neste escopo
// ainda mantém acesso a todos os globais
} ());
Observe os colchetes mais externos deste par envolvendo funções anônimas. Devido às características do idioma do JavaScript, isso é necessário para os colchetes. As declarações que começam com a função de palavra -chave no JS são sempre consideradas declarativas de função. Enrole este código entre colchetes para que o intérprete saiba que esta é uma expressão de função.
Importação variável global
O JavaScript possui um recurso chamado variáveis globais implícitas. Não importa onde um nome de variável seja usado, o intérprete encontrará a declaração de declaração VAR da variável ao contrário de acordo com a cadeia do escopo. Se a declaração de declaração VAR não for encontrada, essa variável será considerada uma variável global. Se essa variável for usada em uma declaração de atribuição e a variável não existir, uma variável global será criada. Isso significa que é fácil usar ou criar variáveis globais em fechamentos anônimos. Infelizmente, isso torna o código escrito extremamente difícil de manter, porque, para os sentimentos intuitivos das pessoas, é impossível dizer rapidamente que essas variáveis são globais.
Felizmente, nossas funções anônimas fornecem soluções alternativas simples. Basta passar na variável global como um parâmetro em nossa função anônima, você pode obter um código mais claro e mais rápido que a variável global implícita. Aqui está um exemplo:
A cópia do código é a seguinte:
(função ($, yahoo) {
// Agora tem acesso ao Globals JQuery (como $) e Yahoo neste código
} (jQuery, Yahoo));
Exportação do módulo
Às vezes, você deseja não apenas usar variáveis globais, mas também as declarar para uso repetido. Podemos fazer isso facilmente derivando -os - através do valor de retorno das funções anônimas. Fazer isso concluirá um modelo modular básico, e o seguinte será um exemplo completo:
A cópia do código é a seguinte:
var módulo = (function () {
var my = {},
privateVariable = 1;
função privatemethod () {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
devolver meu;
} ());
Observe que declaramos um módulo global chamado Módulo, que possui 2 propriedades públicas: um método chamado Module.ModuleMethod e uma variável chamada Module.ModuleProperty. Além disso, mantém um estado interno privado que utiliza fechamentos de funções anônimas. Ao mesmo tempo, podemos importar facilmente as variáveis globais necessárias e usar esse padrão modular, como aprendemos antes.
Modo avançado
A base descrita na seção acima é suficiente para lidar com muitas situações e agora podemos desenvolver ainda mais esse modelo modular para criar estruturas mais poderosas e escaláveis. Vamos começar com o módulo do módulo e apresentar esses modos avançados um por um.
Modo de zoom
Todo o módulo deve ser uma limitação do modo modular em um arquivo. Qualquer pessoa envolvida em um grande projeto entenderá o valor de dividir vários arquivos com JS. Felizmente, temos uma ótima implementação para amplificar os módulos. Primeiro, importamos um módulo, adicionamos propriedades e, finalmente, exportamos. Aqui está um exemplo - amplie o módulo original:
A cópia do código é a seguinte:
var módulo = (function (my) {
my.anothermethod = function () {
// Método adicionado ...
};
devolver meu;
}(MÓDULO));
Usamos a palavra -chave VAR para garantir a consistência, embora não seja necessária aqui. Depois que esse código é executado, nosso módulo já possui um novo método público chamado Module.anothermethod. Este arquivo ampliado também manterá seu próprio estado interno privado e objetos importados.
Modo de zoom amplo
Nosso exemplo acima exige que nosso módulo de inicialização seja executado primeiro e depois o módulo amplificado a ser executado e, é claro, às vezes isso pode não ser necessariamente necessário. Uma das melhores aplicações de JavaScript pode fazer para melhorar o desempenho é executar scripts de forma assíncrona. Podemos criar módulos de multipartamento flexíveis e permitir que eles sejam carregados em qualquer ordem através de um amplo modo de zoom. Cada arquivo precisa ser organizado na seguinte estrutura:
A cópia do código é a seguinte:
var módulo = (function (my) {
// Adicionar recursos ...
devolver meu;
} (Módulo || {}));
Nesse padrão, a expressão VAR torna necessário. Observe que, se o módulo não tiver sido inicializado, essa instrução de importação criará um módulo. Isso significa que você pode usar uma ferramenta como o LABJS para carregar todos os seus arquivos de módulo em paralelo sem ser bloqueado.
Modo de aumento apertado
O modo amplo enorme é muito bom, mas também colocará algumas limitações no seu módulo. Mais importante ainda, você não pode substituir com segurança as propriedades de um módulo. Você não pode usar propriedades de outros arquivos ao inicializar (mas pode usá -los ao executar). O modo de aumento apertado contém uma sequência carregada e permite a substituição de propriedades. Aqui está um exemplo simples (zoom em nosso módulo original):
A cópia do código é a seguinte:
var módulo = (function (my) {
var Old_moduleMethod = my.modulemethod;
my.moduleMethod = function () {
// substituir o método, tem acesso ao antigo através do Old_moduleMethod ...
};
devolver meu;
}(MÓDULO));
Substituímos a implementação do Module.ModuleMethod no exemplo acima, mas, quando necessário, podemos manter uma referência ao método original.
Clone e herança
A cópia do código é a seguinte:
var module_two = (function (antigo) {
var my = {},
chave;
para (chave em antigo) {
if (Old.HasownProperty (key)) {
meu [key] = antigo [chave];
}
}
var super_modulemethod = antigo.modulemethod;
my.moduleMethod = function () {
// Substituir o método no clone, acesso a super através de super_modulemethod
};
devolver meu;
}(MÓDULO));
Este modelo é provavelmente a opção mais inflexível. Isso faz com que o código pareça limpo, mas isso tem o custo da flexibilidade. Como escrevi acima, se uma propriedade for um objeto ou função, ela não será copiada, mas se tornará a segunda referência ao objeto ou função. Se você modificar um deles, modificará o outro ao mesmo tempo (nota do tradutor: porque eles são simplesmente um!). Isso pode ser resolvido pelo processo de clonagem recursiva, mas a clonagem de funções não pode ser resolvida, talvez possa ser resolvida com avaliação. Portanto, estou dizendo a esse método neste artigo apenas leva em consideração a integridade do artigo.
Variáveis privadas de arquivos cruzados
Há uma limitação significativa para dividir um módulo em vários arquivos: cada arquivo mantém suas próprias variáveis privadas e não pode acessar variáveis privadas para outros arquivos. Mas esse problema pode ser resolvido. Aqui está um exemplo de um módulo amplo que mantém variáveis privadas entre os arquivos:
A cópia do código é a seguinte:
var módulo = (function (my) {
var _private = my._private = my._private || {},
_seal = my._seal = my._seal || function () {
exclua my._private;
exclua my._seal;
exclua my._unseal;
},
_unseal = my._unseal = my._unseal || function () {
my._private = _private;
my._seal = _seal;
my._unseal = _unseal;
};
// acesso permanente a _private, _seal e _unseal
devolver meu;
} (Módulo || {}));
Todos os arquivos podem definir propriedades em suas respectivas variáveis _private e entende que elas podem ser acessadas por outros arquivos. Depois que este módulo for carregado, o aplicativo pode chamar o módulo._seal () para impedir chamadas externas para _private interno. Se este módulo precisar ser re-magnificado, o método interno em qualquer arquivo poderá ligar para _UNSEAL () antes de carregar o novo arquivo e ligar para _seal () novamente após a execução do novo arquivo. Eu uso esse padrão no trabalho agora e não o vi em nenhum outro lugar. Eu acho que este é um modelo muito útil e vale a pena escrever um artigo sobre esse modelo em si.
Submódulos
Nosso último modo avançado é obviamente o mais fácil. Existem muitos exemplos excelentes de criação de submódulos. É como criar um módulo normal:
A cópia do código é a seguinte:
Module.sub = (function () {
var my = {};
// ...
devolver meu;
} ());
Embora isso pareça simples, acho que vale a pena mencionar aqui. Os submódulos têm todas as vantagens avançadas dos módulos gerais, incluindo modo de amplificação e estado de privatização.
para concluir
A maioria dos modos avançados pode ser combinada para criar um modo mais útil. Se eu realmente quiser recomendar um padrão modular para projetar aplicativos complexos, eu escolheria combinar amplo modo de amplificação, variáveis privadas e submódulos.
Não considerei o desempenho desses modos, mas prefiro transformar isso em uma maneira mais simples de pensar: se um modo modular tiver um bom desempenho, ele pode fazer um ótimo trabalho ao minimizá -lo, tornando mais rápido o download deste arquivo de script. O uso do modo de ampliação amplo permite downloads paralelos simples sem bloqueio, que aceleram downloads. O tempo de inicialização pode ser um pouco mais lento que outros métodos, mas vale a pena depois de pesar os prós e os contras. Desde que a importação de variável global seja precisa, o desempenho do tempo de execução deve ser afetado e também é possível obter velocidades de corrida mais rápidas nos submódulos, reduzindo a cadeia de referência com variáveis privadas.
Como conclusão, aqui está um exemplo de um módulo filho carregando dinamicamente o módulo pai (criando -o se o módulo pai não existir). Por simplicidade, removi as variáveis privadas e, é claro, é muito simples adicionar variáveis privadas. Esse padrão de programação permite que uma base de código de estrutura hierárquica complexa seja carregada em paralelo por meio de submódulos.
A cópia do código é a seguinte:
var util = (função (pai, $) {
var my = parent.ajax = parent.ajax || {};
my.get = function (url, params, retorno de chamada) {
// ok, então estou trapaceando um pouco :)
retornar $ .getjson (url, params, retorno de chamada);
};
// etc ...
devolver pai;
} (Util || {}, jQuery));
Este artigo resume as melhores práticas atuais de "Javascript Modular Programming" e explica como colocá -lo em prática. Embora este não seja um tutorial primário, você pode entendê -lo apenas um pouco de compreensão da sintaxe básica do JavaScript.