Como Envolver Correctamente uma Função JavaScript

, Author

Aplicar funções JavaScript permite-lhe adicionar lógica comum a funções que não controla, como funções nativas e externas. Muitas bibliotecas JavaScript, como os agentes do TrackJS, necessitam de envolver funções externas para fazer o seu trabalho. A adição de wrappers permite-nos ouvir Telemetria, erros e logs no seu código, sem necessitar de chamar explicitamente a nossa API.

Pode querer embrulhar uma função para adicionar instrumentação ou lógica de depuração temporária. Você também pode alterar o comportamento de uma biblioteca externa sem precisar modificar o código fonte.

Basic Function Wrapping

Porque o JavaScript é maravilhosamente dinâmico, podemos embrulhar uma função simplesmente redefinindo a função com algo novo. Por exemplo, considere este embrulho de myFunction:

Neste exemplo trivial, embrulhamos o original myFunction e adicionamos uma mensagem de registo. Mas há muitas coisas que não tratámos:

  • Como passamos os argumentos da função?
  • Como mantemos o escopo (o valor de this)?
  • Como obtemos o valor de retorno?
  • E se acontecer um erro?

Para lidar com estas coisas, precisamos de ser um pouco mais espertos no nosso embrulho.

Notem que não estamos apenas a invocar a função neste exemplo, mas call-ingindo-a com o valor para this e argumentos a, b, e c. O valor de this será passado de onde quer que você anexe sua função embalada, Window neste exemplo.

>

Também rodeamos toda a função num bloco de try/catch para que possamos invocar a lógica personalizada em caso de erro, rethrow it, ou retornar um valor padrão.

Advanced Function Wrapping

O exemplo básico de wrapping funcionará 90% do tempo, mas se estiver a construir bibliotecas partilhadas, como os agentes TrackJS, isso não é suficientemente bom! Para embrulhar as nossas funções como um profissional, existem alguns casos de bordas com os quais devemos lidar:

  • E que tal argumentos não declarados ou desconhecidos?
  • Como fazemos corresponder a assinatura da função?
  • Como espelhamos as propriedades da função?

Existem 3 subtis mas importantes alterações. Primeiro (#1), nós nomeamos a função. Parece redundante, mas o código do utilizador pode verificar o valor de function.name, por isso é importante manter o nome quando se faz o wrapping.

A segunda alteração (#2) está em como chamamos a função wrapped, usando apply em vez de call. Isto permite-nos passar por um objecto arguments, que é um objecto tipo array-like de todos os argumentos passados para a função em tempo de execução. Isto permite-nos suportar funções que podem ter um número indefinido ou variável de argumentos.

Com apply, não precisamos dos argumentos a, b, e c definidos na assinatura da função. Mas continuando a declarar os mesmos argumentos que a função original, mantemos a aridade da função. Ou seja, Function.length devolve o número de argumentos definidos na assinatura, e isto irá espelhar a função original.

A alteração final (#3) copia quaisquer propriedades especificadas pelo utilizador da função original para o nosso wrapping.

Limitações

Este wrapping é completo, mas existem sempre limitações no JavaScript. Especificamente, é difícil embrulhar corretamente uma função com um protótipo não-padrão, como um construtor de objetos. Este é um caso de uso melhor resolvido por herança.

Em geral, alterar o protótipo de uma função é possível, mas não é uma boa ideia. Existem sérias implicações de performance e efeitos colaterais não intencionais na manipulação de protótipos.

Respeitar o Ambiente

O embrulho da função dá-lhe muita potência para instrumentar e manipular o ambiente JavaScript. Você tem a responsabilidade de manusear esse poder de forma sensata. Se está a construir invólucros funcionais, certifique-se de respeitar o utilizador e o ambiente em que está a operar. Pode haver outros wrappers no local, outros ouvintes anexados para eventos e expectativas sobre as APIs de funções. Ande levemente e não quebre o código externo.

Deixe uma resposta

O seu endereço de email não será publicado.