Skip to content

Latest commit

 

History

History
123 lines (75 loc) · 4.76 KB

File metadata and controls

123 lines (75 loc) · 4.76 KB

A sintaxe de "new Function"

Existe mais uma maneira de criar uma função. Ela é raramente usada, mas às vezes não existem alternativas.

Sintaxe

A sintaxe para criar uma função:

let func = new Function ([arg1, arg2, ...argN], functionBody);

A função é criada com os argumentos arg1...argN e entregue para functionBody.

É mais fácil de compreender olhando um exemplo. Aqui está uma função com dois argumentos:

let sum = new Function('a', 'b', 'return a + b');

alert( sum(1, 2) ); // 3

E aqui está uma função sem argumentos, apenas com o corpo da função:

let sayHi = new Function('alert("Olá")');

sayHi(); // Olá

A principal diferença de outras formas que vimos é a função ser criada literalmente a partir de uma string, e passada em tempo de execução.

Todas as declarações anteriores requeriam de nós, programadores, escrever o código da função dentro do script.

Mas new Function permite transformar qualquer string em uma função. Por exemplo, nós podemos receber uma nova função de um servidor e executa-la:

let str = ... recebe o código de um servidor dinamicamente ...

let func = new Function(str);
func();

É usado em casos muito específicos, como quando recebemos código de um servidor, ou para compilar dinamicamente uma função a partir de um template, em aplicações web complexas.

Closure

Normalmente, uma função lembra onde nasceu na propriedade especial [[Environment]]. Ela faz referência ao Ambiente Lexical de onde foi criado (abordaremos isso no capítulo info:closure).

Mas quando uma função é criada usando new Function, seu [[Environment]] é definido para fazer referência não ao Ambiente Lexical atual, mas ao ambiente global.

Portanto, tal função não tem acesso a variáveis ​​externas, apenas a variáveis globais.

function getFunc() {
  let value = "teste";

*!*
  let func = new Function('alert(value)');
*/!*

  return func;
}

getFunc()(); // erro: value não foi definido

Compare-a com o comportamento padrão:

function getFunc() {
  let value = "teste";

*!*
  let func = function() { alert(value); };
*/!*

  return func;
}

getFunc()(); // *!*"teste"*/!*, do escopo léxico de getFunc

Essa característica especial de new Function parece estranha, mas se apresenta muito útil, na prática.

Imagine que nós precisamos criar uma função a partir de uma string. O código dessa função é desconhecido durante a escrita do script (por esse motivo, nós não usamos funções regulares), mas vai ser conhecido durante o processo de execução. Nós podemos receber do servidor ou de outra fonte.

Nossa nova função precisa interagir com o script principal.

E se você pudesse acessar as variáveis ​​externas?

O problema é que antes de o JavaScript ser publicado para produção, ele é comprimido usando um "minificador" -- um programa especial que encolhe código removendo comentários, espaços e -- o mais importante, renomeia variáveis locais em variáveis mais curtas.

Por exemplo, se uma função tem uma variável let userName, o minificador a troca por let a (ou outra letra se esta estiver ocupada), e ele faz isso em toda parte. Isso usualmente é uma coisa segura de se fazer, por a variável ser local, nada fora da função pode acessar ela. E dentro da função, o minificador troca todas as suas menções. Minificadores são inteligentes, eles analisam a estrutura do código, para que eles não quebrem nada. Eles não são um simples não-inteligente "encontra-e-substitui".

Portanto, se new Function tivesse acesso a variáveis ​​externas, não seria possível encontrar userName renomeado.

Se a new Function tivesse acesso a variáveis ​​externas, haveria problemas com minificadores.

Além disso, esse código seria arquitetonicamente ruim e sujeito a erros.

Para passar algo para uma função, criada como new Function, devemos usar seus argumentos.

Resumo

A sintaxe:

let func = new Function ([arg1, arg2, ...argN], functionBody);

Por razões históricas, os argumentos também podem ser apresentados como uma lista separada por vírgulas.

Estas três declarações significam o mesmo:

new Function('a', 'b', 'return a + b'); // sintaxe básica
new Function('a,b', 'return a + b'); // separados por vírgula
new Function('a , b', 'return a + b'); // separados por vírgula com espaços

Funções criadas com new Function têm [[Environment]] referenciando o ambiente lexical global, não o externo. Portanto, eles não podem usar variáveis ​​externas. Mas isso é realmente bom, porque nos protege contra erros. Passar parâmetros explicitamente é um método muito melhor do ponto de vista arquitetônico e não causa problemas com minificadores.