Devo colocar funções que são usadas apenas em uma outra função, dentro dessa função?

28

Especificamente, estou escrevendo em JavaScript.

Digamos que minha função principal seja a Função A. Se a Função A faz várias chamadas para a Função B, mas a Função B não é usada em nenhum outro lugar, então devo simplesmente colocar a Função B dentro da Função A?

Isso é uma boa prática? Ou devo ainda colocar a Função B no mesmo escopo da Função A?

    
por Gary 06.08.2014 / 21:58
fonte

6 respostas

31

Sou geralmente a favor de funções aninhadas, especialmente em JavaScript.

  • Em JavaScript, a única maneira de limitar a visibilidade de uma função é aninhando-a dentro de outra função.
  • A função auxiliar é um detalhe de implementação particular. Colocá-lo no mesmo escopo é como tornar públicas as funções privadas de uma classe.
  • Se for de uso mais geral, é fácil sair, porque você pode ter certeza de que o assistente atualmente é usado apenas por essa função. Em outras palavras, isso torna seu código mais coeso.
  • Muitas vezes, você pode eliminar parâmetros, o que torna a assinatura e a implementação da função menos detalhadas. Isso não é o mesmo que fazer variáveis globais. É mais como usar um membro da turma em um método particular.
  • Você pode dar às funções auxiliares melhores, nomes mais simples, sem se preocupar com conflitos.
  • A função auxiliar é mais fácil de encontrar. Sim, existem ferramentas que podem ajudar você. Ainda é mais fácil simplesmente mover os olhos para cima na tela um pouco.
  • O código forma naturalmente uma espécie de árvore de abstração: algumas funções gerais na raiz, ramificando-se em vários detalhes de implementação. Se você usar um editor com folding / collapsing de função, o aninhamento cria uma hierarquia de funções intimamente relacionadas no mesmo nível de abstração. Isso torna muito fácil estudar o código no nível necessário e ocultar os detalhes.

Eu acho que muita oposição vem do fato de que a maioria dos programadores foram criados em uma tradição C / C ++ / Java, ou foram ensinados por outra pessoa que era. As funções aninhadas não parecem naturais porque não fomos muito expostas a elas quando estávamos aprendendo a programar. Isso não significa que eles não sejam úteis.

    
por 07.08.2014 / 01:19
fonte
14

Você deve colocá-lo no escopo global, por várias razões.

  • Aninhar uma função auxiliar no chamador aumenta o comprimento do chamador. O comprimento da função é quase sempre um indicador negativo; funções curtas são mais fáceis de entender, memorizar, depurar e manter.

  • Se a função auxiliar tiver um nome sensato, a leitura desse nome será suficiente sem precisar ver a definição próxima. Se você fizer precisar ver a definição de ajuda para entender a função do chamador, então o chamador está fazendo muito ou está trabalhando em muitos níveis de abstração simultaneamente.

  • Ter o auxiliar globalmente disponível permite que outras funções o chamem, se ele for útil, afinal. Se o auxiliar não estiver disponível, você será tentado a recortá-lo e colá-lo, ou para esquecê-lo e reimplementá-lo, mal, ou para tornar outra função mais longa do que deveria ser.

  • Aninhar a função auxiliar aumenta a tentação de usar variáveis do escopo do chamador sem declaração, de modo que não fique claro quais são as entradas e saídas do auxiliar. Se uma função não indicar claramente em quais dados ela opera e quais efeitos ela tem, geralmente é um sinal de responsabilidades pouco claras. Declarar o assistente como uma função autônoma obriga você a saber exatamente o que realmente faz.

Editar

Isso acabou sendo uma questão mais controversa do que eu pensava. Para esclarecer:

Em JavaScript, grandes funções de extensão de arquivos geralmente cumprem o papel de classes porque a linguagem não fornece nenhum outro mecanismo limitador de escopo. Certamente as funções auxiliares devem estar dentro dessas quase-classes, não fora delas.

E o ponto sobre reutilização mais fácil pressupõe que, se uma sub-rotina se tornar mais usada, você está disposto a removê-la completamente e colocá-la no lugar apropriado, por exemplo, uma biblioteca de utilitários de cadeia de caracteres ou em seu registro de configuração global. Se você não quiser ordenar seu código assim, então você pode também aninhar a sub-rotina, como faria com um normal. Objeto de método em uma linguagem mais "blocky".

    
por 06.08.2014 / 22:07
fonte
8

Vou propor um terceiro caminho, para colocar ambas as funções dentro de um fechamento. Seria parecido com:

var functionA = (function(){
    function functionB() {
        // do stuff...
    }

    function functionA() {
        // do stuff...
        functionB();
        // do stuff...
    }

    return functionA;
})();

Criamos o fechamento agrupando a declaração de ambas as funções em uma IIFE . O valor de retorno do IIFE é a função pública, armazenada em uma variável do nome da função. A função pública pode ser invocada exatamente da mesma maneira como se fosse declarada como uma função global, ou seja, functionA() . Note que o valor de retorno é a função , não uma chamada para a função, portanto, nenhum parens no final.

Ao agrupar as duas funções, functionB agora é completamente privado e não pode ser acessado fora do fechamento, mas fica visível apenas para functionA . Ele não está bagunçando o namespace global, e não está sobrecarregando a definição de functionA .

    
por 07.08.2014 / 05:20
fonte
0

Definir a função B dentro da função A dá acesso à função B às variáveis internas de A.

Assim, uma função B definida dentro de uma função A dá a impressão (ou pelo menos a possibilidade) de que B está usando ou alterando as variáveis locais de A. Enquanto definir B fora de A deixa claro que B não.

Portanto, para a clareza do código, eu definiria B dentro de A apenas se B precisar acessar variáveis locais de A. Se B tiver um propósito claro que seja independente de A, eu definitivamente o definiria fora de A.

    
por 16.08.2014 / 16:00
fonte
-1

Você não deve aninhar, porque senão a função aninhada será recriada toda vez que você chamar a função externa.

    
por 13.08.2014 / 21:55
fonte
-3

Como a função B não é usada em nenhum outro lugar, você pode também torná-la uma função dentro da função A, porque essa é a única razão pela qual ela existe.

    
por 13.08.2014 / 08:39
fonte