Angular.js: Como o $ eval funciona e por que é diferente do vanilla eval?

151

Eu estava curioso sobre o que $scope.$evalvocê costuma ver nas diretivas, então verifiquei a fonte e encontrei o seguinte em rootScope.js:

  $eval: function(expr, locals) {
    return $parse(expr)(this, locals);
  },

$parseparece ser definido por ParseProviderin parse.js, que parece definir algum tipo de mini-sintaxe própria (o arquivo tem 900 linhas).

Minhas perguntas são:

  1. O que exatamente está $evalfazendo? Por que ele precisa de sua própria mini linguagem de análise?

  2. Por que o JavaScript antigo simples não está evalsendo usado?

Jonah
fonte
13
$ eval avalia uma expressão angular em relação ao escopo atual .
Mark Rajcok
4
Entre $parseé incrivelmente ótimo.
Fresheyeball 3/13/13

Respostas:

186

$evale $parsenão avalie o JavaScript; eles avaliam expressões AngularJS . A documentação vinculada explica as diferenças entre expressões e JavaScript.

P: O que exatamente $ eval está fazendo? Por que ele precisa de sua própria mini linguagem de análise?

Dos documentos:

Expressões são trechos de código semelhantes ao JavaScript que geralmente são colocados em ligações como {{expression}}. Expressões são processadas pelo serviço $ parse.

É uma mini-linguagem semelhante ao JavaScript que limita o que você pode executar (por exemplo, nenhuma declaração de fluxo de controle, exceto o operador ternário), além de acrescentar um pouco da qualidade do AngularJS (por exemplo, filtros).

P: Por que o javascript antigo "eval" não está sendo usado?

Porque na verdade não está avaliando JavaScript. Como dizem os documentos:

Se ... você deseja executar um código JavaScript arbitrário, deve torná-lo um método de controlador e chamar o método Se você quiser eval () uma expressão angular do JavaScript, use o método $ eval ().

Os documentos vinculados acima têm muito mais informações.

Josh David Miller
fonte
Você disse que $ eval não está avaliando o JavaScript, mas se eu fizer $ eval ("{id: 'val'}"), recebo um objeto JS. (Angular 1.0.8)
Gabriel
7
@Yappli $evalnão avalia JavaScript; avalia expressões AngularJS, que são como um subconjunto mais seguro de JavaScript. "{id: 'val'}"é uma expressão AngularJS válida e deve retornar um objeto JS válido. Veja o link acima para saber a diferença entre expressões e JS regulares.
Josh David Miller
1
Boa resposta, mas não tenho certeza de que "por exemplo, nenhuma declaração de fluxo de controle" seja precisa. Você pode fazer algo assim ... ng-click = "someVal? SomeFunc (someVal): noop", que é uma expressão angular perfeitamente válida
Charlie Martin
@CharlieMartin A documentação diz especificamente "nenhuma declaração de fluxo de controle" , mas seu argumento é válido. No entanto, eu definitivamente não recomendaria isso em um ngClick; esse tipo de lógica quase certamente pertence ao controlador.
Josh David Miller
1
Interessante que os documentos digam que, como o suporte para o operador ternário foi adicionado intencionalmente ... github.com/angular/angular.js/blob/master/src/ng/… O ng-click foi apenas um exemplo simples e eu concordo essa lógica deve estar em um controlador, mas não vejo nada de errado em usar um operador ternário na notação de colchete e a equipe angular obviamente não ou também ou eles não teriam adicionado suporte a ela. Suponho que, se uma correção fosse feita, ela deveria ocorrer nos documentos antes dessa resposta
Charlie Martin
22

Do teste,

it('should allow passing locals to the expression', inject(function($rootScope) {
  expect($rootScope.$eval('a+1', {a: 2})).toBe(3);

  $rootScope.$eval(function(scope, locals) {
    scope.c = locals.b + 4;
  }, {b: 3});
  expect($rootScope.c).toBe(7);
}));

Também podemos transmitir locais para expressão de avaliação.

allenhwkim
fonte
2

Acho que uma das perguntas originais aqui não foi respondida. Acredito que vanilla eval () não seja usada porque aplicativos angulares não funcionariam como aplicativos Chrome, o que impede explicitamente que eval () seja usado por razões de segurança.

Kevin MacDonald
fonte