Estou estudando THREE.js e percebi um padrão em que as funções são definidas assim:
var foo = ( function () {
var bar = new Bar();
return function ( ) {
//actual logic using bar from above.
//return result;
};
}());
(Veja o exemplo do método de raycast aqui ).
A variação normal de tal método seria assim:
var foo = function () {
var bar = new Bar();
//actual logic.
//return result;
};
Comparando a primeira versão com a variação normal , a primeira parece diferir em que:
- Ele atribui o resultado de uma função autoexecutável.
- Ele define uma variável local dentro desta função.
- Ele retorna a função real contendo a lógica que faz uso da variável local.
Portanto, a principal diferença é que na primeira variação a barra é atribuída apenas uma vez, na inicialização, enquanto a segunda variação cria essa variável temporária toda vez que é chamada.
Meu melhor palpite sobre por que isso é usado é que ele limita o número de instâncias de bar (haverá apenas uma) e, portanto, economiza sobrecarga de gerenciamento de memória.
Minhas perguntas:
- Esta suposição está correta?
- Existe um nome para este padrão?
- Por que isso é usado?
javascript
closures
iife
Patrick Klug
fonte
fonte
Respostas:
Suas suposições estão quase corretas. Vamos revisá-los primeiro.
Isso é chamado de expressão de função invocada imediatamente ou IIFE
Essa é a maneira de ter campos de objetos privados em JavaScript, pois de outra forma não fornece a
private
palavra - chave ou funcionalidade.Novamente, o ponto principal é que essa variável local é privada .
AFAIK você pode chamar esse padrão de Módulo de Padrão . Citando:
Comparando esses dois exemplos, meus melhores palpites sobre por que o primeiro é usado são:
Mas se você só precisa do objeto vanilla todas as vezes, então esse padrão provavelmente não adicionará nenhum valor.
fonte
Limita os custos de inicialização do objeto e, adicionalmente, garante que todas as invocações de função usem o mesmo objeto. Isso permite, por exemplo, que o estado seja armazenado no objeto para uso em futuras invocações.
Embora seja possível que isso limite o uso de memória, geralmente o GC coletará objetos não utilizados de qualquer maneira, portanto, esse padrão provavelmente não ajudará muito.
Esse padrão é uma forma específica de fechamento .
fonte
Não tenho certeza se esse padrão tem um nome mais correto, mas isso parece um módulo para mim, e o motivo pelo qual é usado é para encapsular e manter o estado.
O encerramento (identificado por uma função dentro de uma função) garante que a função interna tenha acesso às variáveis dentro da função externa.
No exemplo que você deu, a função interna é retornada (e atribuída a
foo
) executando a função externa, o que significa quetmpObject
continua a viver dentro do encerramento e várias chamadas para a função internafoo()
operarão na mesma instância detmpObject
.fonte
A principal diferença entre o seu código e o código Three.js é que no código Three.js a variável
tmpObject
é inicializada apenas uma vez e, em seguida, compartilhada por cada invocação da função retornada.Isso seria útil para manter algum estado entre as chamadas, semelhante a como as
static
variáveis são usadas em linguagens semelhantes a C.tmpObject
é uma variável privada visível apenas para a função interna.Ele muda o uso da memória, mas não é projetado para economizar memória.
fonte
Eu gostaria de contribuir com esse segmento interessante estendendo para o conceito do padrão de módulo revelador, que garante que todos os métodos e variáveis sejam mantidos privados até que sejam explicitamente expostos.
No último caso, o método de adição seria chamado de Calculator.add ();
fonte
No exemplo fornecido, o primeiro snippet usará a mesma instância de tmpObject para cada chamada à função foo (), onde, como no segundo snippet, tmpObject será uma nova instância todas as vezes.
Uma razão pela qual o primeiro fragmento pode ter sido usado é que a variável tmpObject pode ser compartilhada entre chamadas para foo (), sem que seu valor vaze para o escopo em que foo () é declarado.
A versão da função não executada imediatamente do primeiro snippet seria realmente semelhante a esta:
Observe, entretanto, que esta versão tem tmpObject no mesmo escopo que foo (), portanto, ele pode ser manipulado posteriormente.
A melhor maneira de obter a mesma funcionalidade seria usar um módulo separado:
Módulo 'foo.js':
Módulo 2:
Uma comparação entre o desempenho de um IEF e uma função de criador de foo nomeada: http://jsperf.com/ief-vs-named-function
fonte