Quero escrever uma biblioteca de classe JavaScript eficiente, mas não posso começar;
Tente ler a biblioteca de outras pessoas, mas entenda como se fosse entendida;
Eu pretendo estudar bem o JS avançado funciona bem, mas o conteúdo do livro autoritário é muito disperso.
Mesmo se você se lembra do "uso", não pensa no "método" quando quiser "usar".
Talvez você, como eu, pareça ter uma força invisível que restringe nossos planos, fazendo -nos pensar repetidamente que as limitações do conhecimento nos fizeram ficar paradas e difíceis de avançar.
Durante esse período, vários trabalhos de casa, design de cursos e relatórios experimentais dobraram. É raro espremer um pouco de tempo, nunca dormir e resolver os livros que li no passado apenas para estar mais perto de escrever minha própria biblioteca.
Este artigo é referenciado de "Javascript Language Essence" e "Javascript eficaz". Todos os exemplos foram depurados. Depois de entendê -los, quero tornar alguns princípios "profundos" um pouco mais simples.
1. Escopo variável
O escopo é como oxigênio para os programadores. Está em toda parte, e você nem pensa nisso. Mas quando for poluído (como o uso de objetos globais), você se sentirá asfixia (como a lenta resposta à aplicação). As regras do escopo do JavaScript Core são simples, cuidadosamente projetadas e muito poderosas. O uso eficaz do JavaScript requer dominar alguns dos conceitos básicos de escopo variável e entender algumas situações extremas que podem levar a problemas ilusórios e irritantes.
1.1 Tente usar variáveis globais o mínimo possível
O JavaScript é fácil de criar variáveis em um espaço de nome global. A criação de variáveis globais é fácil porque não requer nenhuma forma de declaração e pode ser acessada automaticamente por todo o código de todo o programa.
Para iniciantes, ao encontrar certas necessidades (por exemplo, quando os dados transmitidos são registrados, aguardando um certo tempo a ser chamado ou quando uma determinada função é frequentemente usada), finalmente pensamos em funções globais. Até o pensamento orientado para o processo de idioma C que aprendi no meu primeiro ano está muito enraizado, e o sistema está perfeitamente cheio de funções. Definir variáveis globais pode poluir os namespaces públicos compartilhados e pode levar a conflitos inesperados de nomeação. As variáveis globais também não são propícias à modularidade, pois causa acoplamento desnecessário entre componentes independentes no programa. Sério falando, muita coisa global (incluindo folhas de estilo, definindo diretamente os estilos de div ou a) e integrá -los aos desenvolvimentos de várias pessoas, será um erro catastrófico. É por isso que todo o código jQuery é envolvido em uma expressão anônima instantaneamente executada - funções anônimas auto -calculadas. Quando o navegador carrega o arquivo jQuery, ele inicia a execução imediatamente após chamar a função anônima, inicializando vários módulos de jQuery para evitar destruir e poluir variáveis globais e afetar outros códigos.
A cópia do código é a seguinte:
(função (janela, indefinida) {
var jQuery = ...
// ...
window.jQuery = Window. $ = jQuery;
})(janela);
Além disso, você pode pensar que é mais conveniente "escrever como você primeiro e organizá -lo mais tarde", mas excelentes programadores prestarão atenção constantemente à estrutura do programa, classificará continuamente as funções relacionadas e separa componentes irrelevantes, e esses comportamentos fazem parte da fórmula de programação.
Como os namespaces globais são a única maneira de os componentes independentes nos programas JavaScript interagirem, o uso de controles de nomeação global é inevitável. Componentes ou bibliotecas precisam definir algumas variáveis globais. Para uso por outras partes do programa. Caso contrário, é melhor usar variáveis locais.
A cópia do código é a seguinte:
this.foo; // indefinido
foo = "global foo";
this.foo; // "global foo"
var foo = "global foo";
this.foo = "alterado";
foo; // alterado
O espaço para nome global do JavaScript também é exposto a objetos globais que podem ser acessados no escopo global do programa, que serve como o valor inicial dessa palavra -chave. Em um navegador da web, o objeto global está vinculado à variável da janela global. Isso significa que existem duas maneiras de criar uma variável global: declare -a com VAR no escopo global ou adicione -o ao objeto global. A vantagem de usar as declarações VAR é que elas podem expressar claramente o impacto das variáveis globais no escopo do programa.
Dado que as referências às variáveis globais vinculadas podem causar erros de tempo de execução, os escopos de poupança claros e concisos facilitarão a compreensão dos usuários do código que as variáveis globais declara o programa.
Como o objeto global fornece um mecanismo de resposta dinâmica para o ambiente global, ele pode ser usado para consultar um ambiente de corrida e detectar quais recursos estão disponíveis nesta plataforma.
EG.ES5 apresenta um objeto JSON global para ler e escrever dados de formato JSON.
A cópia do código é a seguinte:
if (! this.json) {
this.json = {
Parse: ..,
stringify: ...
}
}
Se você fornecer uma implementação do JSON, é claro que poderá usar sua própria implementação de maneira simples e incondicionalmente. Mas as implementações incorporadas fornecidas pelo ambiente do host são quase mais adequadas porque estão escritas no navegador em C. porque eles verificam estritamente a precisão e a consistência de acordo com certos padrões e geralmente fornecem melhor desempenho do que as implementações de terceiros.
A operação básica das seqüências de simulação de design do curso da estrutura de dados exigia que os métodos fornecidos pelo próprio idioma não pudessem ser usados. JavaScript implementa muito bem as operações básicas das matrizes. Se for apenas para necessidades gerais de aprendizagem, a idéia de métodos de simulação fornecida pelo idioma em si é bom, mas se você realmente investe no desenvolvimento, não precisará optar por optar por usar métodos internos de JavaScript o mais rápido possível.
1.2 Evite usar com
A declaração com qualquer "conveniência" que torne seu aplicativo não confiável e ineficiente. Precisamos chamar uma série de métodos em um único objeto por sua vez. O uso da instrução com com a declaração pode facilmente evitar referências duplicadas a objetos:
A cópia do código é a seguinte:
Status da função (info) {
var widget = new widget ();
com (widget) {
revés ("azul");
Setforeground ("branco");
setText ("status:"+info);
mostrar();
}
}
Também é muito tentador usar a instrução com "importar" (importar) variáveis de um objeto de módulo.
A cópia do código é a seguinte:
função f (x, y) {
com (matemática) {
retornar min (redondo (x), sqrt (y)); // citação abstrata
}
}
De fato, o JavaScript trata todas as variáveis iguais. O JavaScript começa no escopo mais interno e procura variáveis para fora. O idioma com a linguagem trata um objeto como se represente um escopo variável; portanto, dentro do bloco de código, as pesquisas variáveis começam pesquisando atributos do nome da variável fornecida. Se a propriedade não for encontrada neste objeto, continue pesquisando no escopo externo. A referência a cada variável externa no bloco com o bloco assume implicitamente que não há atributo com o mesmo nome no objeto com (e qualquer um de seus objetos de protótipo). Criar ou modificar um objeto com ou seu protótipo em outras partes do programa não segue necessariamente essas suposições. O mecanismo JavaScript certamente não lê o código local para obter essas variáveis locais que você está usando. O escopo do JavaScript pode ser representado como estruturas de dados internos eficientes, e as pesquisas variáveis são muito rápidas. No entanto, como o bloco de código com código precisa procurar a cadeia de protótipo do objeto para encontrar todas as variáveis no código com o código, sua velocidade de execução é muito menor que a do bloco de código geral.
Em vez do idioma com linguagem, é simples vincular o objeto a um nome de variável curto.
A cópia do código é a seguinte:
Status da função (info) {
var w = new widget ();
w.setbackground ("azul");
w.setforeground ("branco");
w.settext ("status:"+info);
w.show ();
}
Em outros casos, a melhor maneira é ligar explicitamente variáveis locais a propriedades relevantes.
A cópia do código é a seguinte:
função f (x, y) {
var min = math.min,
redond = Math.Round,
sqrt = math.sqrt;
retornar min (redonda (x), sqrt (y));
}
1.3 Proficiente no fechamento
Há um único conceito para entender o fechamento:
a) JavaScript permite que você faça referência a variáveis definidas fora da função atual.
A cópia do código é a seguinte:
função makendwich () {
var MagicingRedient = "manteiga de amendoim";
função make (preenchimento) {
return magicingredredent + "e" + preenchimento;
}
retornar make ("geléia");
}
makendwich (); // "manteiga de amendoim e geléia"
b) Mesmo que a função externa tenha retornado, a função atual ainda poderá se referir à variável definida pela função externa.
A cópia do código é a seguinte:
função makendwich () {
var MagicingRedient = "manteiga de amendoim";
função make (preenchimento) {
return magicingredredent + "e" + preenchimento;
}
retornar make;
}
var f = sandwichmaker ();
f ("geléia"); // "manteiga de amendoim e geléia"
f ("bananas"); // "manteiga de amendoim e bananas"
F ("Mallows"); // "manteiga de amendoim e mallow"
Os valores de função do JavaScriptd contêm mais informações do que o código necessário para executar quando são chamados. Além disso, os valores da função JavaScript também armazenam internamente as variáveis às quais podem se referir definidos em seu escopo fechado. Essas funções que rastreiam variáveis dentro do escopo que cobrem são chamadas de fechamento.
A função Make é um fechamento cujo código se refere a duas variáveis externas: MagicingRedient e preenchimento. Sempre que a função Make é chamada, seu código pode se referir a essas duas variáveis porque o fechamento armazena essas duas variáveis.
Uma função pode se referir a qualquer variável em seu escopo, incluindo parâmetro e variáveis de função externa. Podemos usar isso para escrever funções mais gerais de sanduíche.
A cópia do código é a seguinte:
função makendwich (MagicingRedient) {
função make (preenchimento) {
return magicingredredent + "e" + preenchimento;
}
retornar make;
}
var f = sandwichmaker ("ham");
f ("queijo"); // "presunto e queijo"
f ("mostarda"); // "presunto e mostarda"
Os fechamentos são uma das características mais elegantes e expressivas do JavaScript e também são o núcleo de muitos idiomas.
c) O fechamento pode atualizar o valor de uma variável externa. De fato, os fechamentos da loja de referências a variáveis externas, não cópias de seus valores. Portanto, qualquer fechamento com acesso a essas variáveis externas pode ser atualizado.
A cópia do código é a seguinte:
caixa de função () {
var val = indefinido;
retornar {
set: function (newval) {val = newval;},
get: function () {return val;},
Tipo: function () {return typeof val;}
};
}
var b = box ();
B.Type (); //indefinido
B.set (98.6);
b.get (); // 98.6
B.Type (); // Número
Este exemplo produz um objeto contendo três fechamentos. Esses três fechamentos são definidos, digitam e obtêm propriedades, e todos compartilham acesso às variáveis Val e o fechamento do conjunto atualiza o valor do Val. Em seguida, ligue para obter e digitar para visualizar os resultados atualizados.
1.4 Entenda a melhoria da declaração variável
O JavaScript suporta esse escopo de método (as referências à variável Foo estarão vinculadas ao escopo que declara mais próximo da variável Foo), mas não suporta o escopo no nível do bloco (o escopo definido pela variável não é a instrução ou bloco de código fechado mais próximo).
Não entender esse recurso levará a alguns bugs sutis:
A cópia do código é a seguinte:
função iswinner (jogador, outros) {
var mais alto = 0;
for (var i = 0, n = outros.length; i <n; i ++) {
var player = outros [i];
if (player.score> mais alto) {
mais alto = player.score;
}
}
Return player.score> mais alto;
}
1.5 Cuidado com o escopo desajeitado de expressões de função de nomeação
A cópia do código é a seguinte:
função dupla (x) {return x*2; }
var f = função (x) {return x*2; }
O mesmo código de função também pode ser usado como expressão, mas tem significados completamente diferentes. A diferença oficial entre as funções anônimas e as expressões de função nomeada é que o último está ligado a uma variável com o mesmo nome de função que seu nome de função, que serve como uma variável local da função. Isso pode ser usado para escrever expressões de função recursiva.
A cópia do código é a seguinte:
var f = função encontre (árvore, chave) {
// ...
Return encontre (árvore.left, chave) ||
encontre (árvore.right, chave);
}
Vale ressaltar que o escopo da variável achado está apenas em sua própria função. Diferentemente das declarações de função, as expressões de função nomeadas não podem ser referenciadas externamente através de seu nome de função interna.
A cópia do código é a seguinte:
encontre (mytree, "foo"); // error: find não está definido;
var construtor = function () {return null; }
var f = function () {
retorno construtor ();
};
f (); // {} (em ambientes ES3)
O programa parece produzir nulo, mas na verdade produzirá um novo objeto.
Como a variável de função nomeada herda objeto.prototype.Constructor (isto é, o construtor do objeto), assim como nas declarações, esse escopo será afetado pelas alterações dinâmicas do objeto.prototipo. A maneira de evitar o objeto que contaminam o escopo das expressões de função no sistema é evitar adicionar propriedades no objeto.Prototipo a qualquer momento para evitar o uso de variáveis locais com o mesmo nome que a propriedade Standard.Prototype.
Outra desvantagem no popular mecanismo JavaScript é a promoção da declaração das expressões de função nomeada.
A cópia do código é a seguinte:
var f = função g () {return 17;}
g (); // 17 (em ambiente não -conformista)
Alguns ambientes JavaScript usam até as duas funções F e G como objetos diferentes, resultando em alocação de memória desnecessária.
1.6 Cuidado com o escopo desajeitado para funções de blocos locais
A cópia do código é a seguinte:
função f () {return "global"; }
teste de função (x) {
função f () {return "local";}
var resultado = [];
if (x) {
resultado.push (f ());
}
resultado.push (f ());
resultado resultado resultante;
}
teste (verdadeiro); // ["Local", "Local"]
teste (falso); //["local"]
A cópia do código é a seguinte:
função f () {return "global"; }
teste de função (x) {
var resultado = [];
if (x) {
função f () {return "local";}
resultado.push (f ());
}
resultado.push (f ());
resultado resultado resultante;
}
teste (verdadeiro); // ["Local", "Local"]
teste (falso); //["local"]
O JavaScript não possui escopo no nível do bloco, portanto, o escopo da função interna f deve ser a função de teste inteira. Alguns ambientes JavaScript fazem, mas nem todos os ambientes JavaScript. As implementações do JavaScript relatam funções como erros no modo rigoroso (programas em modo rigoroso com declarações de funções de bloco local relatarão como um erro de sintaxe), o que ajuda a detectar código não portável, fornecendo mais sábios e possíveis semânticas para as declarações de funções locais para versões padrão futuras. Nesse caso, é possível considerar declarar uma variável local dentro da função de teste para apontar para a função global f.