Usando um fecho para organizar declarações de protótipo

Isso provavelmente precisa de uma boa limpeza, mas espero que ajude a todos ao escrever um novo objeto de protótipo. É para isso que gravitei nos últimos anos, escrevendo protótipo após protótipo. Certamente não é necessário para objetos simples, mas para verdadeiros protótipos, este é um ótimo estilo de codificação. No momento, encorajamos nossos desenvolvedores a seguir este estilo, pois parece manter tudo limpo.

O estilo de codificação Prototype Closure utiliza métodos de prototipagem JavaScript padrão dentro de um closure para organizar melhor o código relacionado ao objeto.

Resumo Geral de Fechamento

O estilo de codificação Prototype Closure organiza o construtor e os métodos de protótipo dentro de um closure para fácil identificação do objeto prototype.

var AdditionUtility = (function(){
var Constructor = function(value){
this.value = value || 0;
};

Constructor.prototype = {
value: null,
add: function(numToAdd) {
this.value += numToAdd;
}
};

return Constructor;
})();

No topo da função de fechamento, o construtor é declarado. Depois disso, propriedades, setters, getters e métodos são definidos na propriedade prototype. Este tipo de estilo de codificação visa restringir a declaração do construtor, propriedades e métodos dentro do encerramento para garantir a organização. Um programador de uma linguagem de programação tradicional orientada a objetos, bem como um desenvolvedor de JavaScript experiente, deve ser capaz de identificar e modificar facilmente esse objeto e suas propriedades. As principais coisas que estamos tentando garantir aqui são: Legibilidade e Organização do Código (que contribuem para a sustentabilidade). Também torna o código mais portátil, visto que o objeto não está fortemente acoplado a outros protótipos, funções ou objetos.

Diretrizes

Embora o analisador não force um padrão específico de codificação ao usar qualquer método de declaração de objeto de protótipo, é importante estabelecer e cumprir as diretrizes pelas quais cada objeto de protótipo será construído e utilizado. Alguns deles serão expandidos posteriormente.

Declaração do Construtor

A ilustração mais simples do padrão Prototype Closure é o exemplo dado acima. Como regra geral, você deve nomear a função principal como “Construtor” para se distinguir no código. Essa variável está apenas no escopo do Fechamento, é claro, e não será acessível fora dele. Em vez disso, você usaria o AdditionUtilityobjeto, que conterá o objeto Prototype resultante.

Declaração de objeto de protótipo

Usando esse estilo de codificação, normalmente declaro o objeto de protótipo em uma única instrução. Para estender outros protótipos, geralmente me refiro a Object.create do ECMAScript 5. Para a criação de objeto de protótipo padrão, como visto na linha 6 do exemplo acima, simplesmente utilizo a sintaxe literal de objeto do JavaScript.

Um exemplo de Object.create pode ser encontrado no MDN

Declaração de Propriedade

Em minha experiência com isso, as propriedades devem sempre ser declaradas dentro do objeto de protótipo como uma prática recomendada. Isso permitirá que você defina setters, getters ou propriedades literais e também garantirá a legibilidade e a organização adequada do código em relação a esse padrão.

TODAS as propriedades devem ser declaradas e inicializadas se forem utilizadas dentro do objeto. Nunca deve haver uma declaração de uma nova propriedade dentro de um método. SEMPRE declare todas as suas propriedades dentro da closure e então defina seus valores em seus métodos apropriados.

Como prática recomendada, normalmente não defino o valor de uma propriedade dinamicamente na declaração de propriedade e, em vez disso, faço isso em métodos (por exemplo, no construtor). Normalmente, o único valor que uma propriedade recebe durante sua declaração é um valor primitivo (string, número, booleano, nulo, indefinido, etc …)

Observe também o método inerente do JavaScript de referenciar o valor de uma variável para não primitivo. Ao declarar um objeto ou array como uma propriedade dentro do closure, ao invés de null ou undefined e então instanciar o objeto ou array dentro do construtor ou método, uma referência é armazenada na propriedade, ao invés do objeto real. Por causa disso, todas as instâncias futuras do objeto de protótipo conterão uma referência a esse objeto, em vez de uma nova instância para cada nova instância de seu objeto de protótipo.

Explicado:

var Foo = { "greeting": "Hello" }, Bar;
Bar = Foo;
Bar.greeting = "Hello World";
console
.log(Foo.greeting);

No exemplo acima, um objeto foi instanciado com uma propriedade “greeting” cujo valor era “Hello”, e uma referência a esse objeto foi armazenada na variável “Foo”, ligando os dois.

Na linha 2 ( ), a referência ao referido objeto foi copiada , ao invés do objeto real. Por causa disso, ambos e agora apontam para o mesmo objeto. Assim, as alterações na propriedade também são refletidas na variável.Bar = FooBarBarFoogreetingFoo

A última declaração no exemplo acima irá alertar "Hello World", ao invés de "Hello".

Para garantir a exclusividade entre os objetos de protótipo instanciados, é aconselhável declarar objetos e matrizes dentro do construtor ou métodos, em vez de durante a declaração dentro do encerramento. Em vez disso, essas propriedades devem ser declaradas como “nulas” ou “indefinidas”, com um comentário fazendo referência ao nome do método no qual foram definidas inicialmente.

Declarações de objeto, entretanto, são permitidas ao criar explicitamente um “global” que todos os objetos instanciados compartilharão, como um objeto defaultOptions, que deve ser o mesmo em todos os objetos instanciados.

Declaração Setter / Getter

As melhores práticas exigem que Setters e Getters sejam sempre declarados após as propriedades dentro da declaração do objeto de protótipo, como no exemplo abaixo.

Ao usar Setters e Getters em referência a uma variável de contraparte, a propriedade de contraparte deve sempre ter o mesmo nome que o setter ou getter prefixado com um sublinhado como uma prática recomendada. Isso também é ilustrado no exemplo abaixo, na linha 4.

Constructor.prototype = {
foo
: null,

set bar: function(val){
this._bar = val;
},

get bar: function(val){
return this._bar;
}
};

Assim como em um Descritor de Propriedade para uso com a funcionalidade Object.create, Setters e Getters para a mesma referência de propriedade devem ser agrupados, de preferência na ordem de :; isso é descrito no exemplo acima. Da mesma forma, getters não devem ser agrupados com getters e setters não devem ser agrupados com setters, em vez disso, eles devem ser agrupados por sua referência de propriedade compartilhada, para garantir a legibilidade.setter, getter

Declaração de Método

Os métodos sempre devem ser declarados após as propriedades, setters e getters.

Como regra geral, os métodos devem ser declarados na seguinte ordem:

  1. métodos públicos (camel-case)
  2. métodos pseudo-privados (camel-case, prefixado com dois sublinhados “__”)
  3. métodos utilitários (como toString, etc …)

Métodos pseudo-privados devem ser precedidos de dois sublinhados (por exemplo ). Seu status “privado” deve ser honrado e, portanto, eles nunca devem ser chamados de fora do próprio objeto de protótipo. Como o JavaScript não honra métodos privados, não é possível impedir o acesso a esses métodos fora do próprio objeto, exceto por convenções.this.__generateKey()

Declarações não declarativas no escopo imediato do fechamento

Para manter a legibilidade e garantir a codificação adequada de objetos, nunca deve haver instruções não declarativas no escopo imediato do encerramento. Todo o código lógico deve estar contido no construtor, métodos ou setters / getters para garantir que as práticas recomendadas sejam seguidas.

Nenhuma instrução deve estar contida imediatamente no encerramento, exceto para a declaração do construtor, a declaração do objeto de protótipo e a instrução de retorno.

Execução e Utilização

Instanciação

var AdditionUtility = (function(){
[...]
})();

var Y = new AdditionUtility(13);

A instanciação normalmente é feita usando o operador “novo”. No processo de instanciação, o parser executa o construtor que começa na linha 2 do primeiro exemplo desta dica.

Padrão Singleton

Por causa do design do padrão Prototype Closure, a instanciação pode ser feita para o fechamento para produzir um objeto semelhante a um “singleton”. Com isso, o protótipo ainda está disponível por meios tradicionais para adaptação a outros objetos usando Object.create, mas isso fornece uma maneira limpa de criar um objeto simples que deve ser usado apenas uma vez, sem a necessidade de duas variáveis ​​(uma contendo o protótipo objeto, o outro contendo uma versão instanciada do referido objeto). Nesse caso, os parâmetros seriam passados ​​para o fechamento e alimentados automaticamente para o construtor. A forma singleton deste padrão difere ligeiramente e pode ser revisada no exemplo abaixo:

var Test = (function(){
var Constructor = function(message,obj) {
console
.log(message);
this.obj = obj;
};
return new Constructor(
"Hello World!",
{ "foo": "bar" }
);
}());

Observe a mudança na sintaxe de encerramento na linha 6. Simplesmente executar a instrução acima produziria uma mensagem no console contendo “Hello World!” e um objeto “Teste” com uma propriedade “obj” cujo valor é delineado no segundo argumento a partir da linha 8.

Utilização e interação

O objeto e suas instâncias funcionarão como qualquer outro objeto de protótipo em JavaScript.

var AdditionUtility = (function(){
var Constructor = function(value){
this.value = value || 0;
};

Constructor.prototype = {
value: null,
add: function(numToAdd) {
this.value += numToAdd;
}
};

return Constructor;
})();
var Y = new AdditionUtility(13);
Y
.add(1);
Y
.value;

O exemplo acima cria uma nova instância de AdditionUtility, passando “13” como o argumento para o parâmetro “valor” no construtor na linha 15.

A última instrução no exemplo de código acima resultaria em “14”.

Como este é um objeto de protótipo, o acesso aos métodos e propriedades estão disponíveis por meio da propriedade “prototype” da variável “AdditionUtility”.

A instrução a seguir produzirá o mesmo resultado de “14”, enquanto utiliza a função Function.prototype.call disponível para todas as variáveis ​​de tipo Function. (Consulte também Function.prototype.apply)

var Z = new AdditionUtility(13);
AdditionUtility.prototype.add.call(Z,1);
Z
.value;

Inconvenientes

Sugestão de código em IDEs e editores

Como o objeto é o resultado da execução de um encerramento, as dicas baseadas no construtor podem não fornecer uma lista de parâmetros para o objeto em alguns IDEs e Editor. Para alguns editores, isso não pode ser evitado. No entanto, descobri que a maioria dos editores respeitará o padrão Prototype Closure e fornecerá sugestões de propriedades e parâmetros adequados para os objetos.

Codificação entre as linhas

Um erro perigoso que um desenvolvedor desinformado ou inexperiente pode cometer é colocar instruções não declarativas fora do construtor ou métodos e dentro do encerramento entre as declarações do construtor ou do objeto protótipo. Isso pode ser perigoso, pois é difícil de ler, pode resultar em comportamento indesejado e, muitas vezes, é resultado da falta de compreensão do desenvolvedor sobre esse tipo de estilo de codificação. Embora o JavaScript e os IDEs não saibam melhor, é importante que os desenvolvedores não escrevam instruções além das declarações do construtor e do protótipo dentro do encerramento. Em vez disso, tente deixar toda a codificação lógica e funcional dentro do construtor e dos métodos.

Veja também