Angular.js: ¿Cómo funciona $ eval y por qué es diferente de vanilla eval?

151

Tenía curiosidad sobre el $scope.$eval que a menudo ves en las directivas, así que revisé la fuente y encontré lo siguiente en rootScope.js:

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

$parseparece estar definido por ParseProviderin parse.js, que parece definir algún tipo de mini-sintaxis propia (el archivo tiene 900 líneas de largo).

Mis preguntas son:

  1. Que es exactamente $eval haciendo ? ¿Por qué necesita su propio lenguaje de análisis mini?

  2. ¿Por qué no evalse usa JavaScript antiguo ?

Jonás
fuente
13
$ eval evalúa una expresión angular contra / en el alcance actual .
Mark Rajcok
44
Por cierto, $parsees increíblemente genial.
Fresheyeball

Respuestas:

186

$evaly $parseno evalúes JavaScript; evalúan expresiones AngularJS . La documentación vinculada explica las diferencias entre expresiones y JavaScript.

P: ¿Qué está haciendo exactamente $ eval? ¿Por qué necesita su propio lenguaje de análisis mini?

De los documentos:

Las expresiones son fragmentos de código similares a JavaScript que generalmente se colocan en enlaces como {{expresión}}. Las expresiones son procesadas por el servicio $ parse.

Es un minilenguaje similar a JavaScript que limita lo que puede ejecutar (por ejemplo, sin sentencias de flujo de control, excepto el operador ternario), así como agrega algo de bondad AngularJS (por ejemplo, filtros).

P: ¿Por qué no se usa javascript "eval"?

Porque en realidad no está evaluando JavaScript. Como dicen los documentos:

Si ... desea ejecutar código JavaScript arbitrario, debe convertirlo en un método controlador y llamar al método. Si desea evaluar () una expresión angular de JavaScript, use el método $ eval ().

Los documentos vinculados a arriba tienen mucha más información.

Josh David Miller
fuente
Dijiste que $ eval en realidad no evalúa JavaScript, pero si hago $ eval ("{id: 'val'}") obtengo un objeto JS. (Angular 1.0.8)
Gabriel
77
@Yappli $evalno evalúa JavaScript; evalúa expresiones AngularJS, que son como un subconjunto más seguro de JavaScript. "{id: 'val'}"es una expresión AngularJS válida y debe devolver un objeto JS válido. Vea el enlace de arriba para ver la diferencia entre expresiones y JS regular.
Josh David Miller
1
Buena respuesta, pero no estoy seguro de que "por ejemplo, no hay declaraciones de flujo de control" es precisa. Puede hacer algo como esto ... ng-click = "someVal? SomeFunc (someVal): noop", que es una expresión angular perfectamente válida
Charlie Martin
@CharlieMartin La documentación dice específicamente "no hay declaraciones de flujo de control" , pero su punto es válido. Sin embargo, definitivamente no recomendaría hacerlo en un ngClick; ese tipo de lógica casi seguramente pertenece al controlador.
Josh David Miller
1
Es interesante que los documentos digan que a medida que el soporte para el operador ternario se agregó intencionalmente ... github.com/angular/angular.js/blob/master/src/ng/… El ng-click fue solo un ejemplo simple y estoy de acuerdo esa lógica debería estar en un controlador, pero no veo nada de malo en usar un operador ternario en la notación de paréntesis y el equipo angular obviamente tampoco lo hace o no habrían agregado soporte para ello. Supongo que si se hiciera una corrección, debería suceder en los documentos antes de esta respuesta
Charlie Martin
22

De la prueba,

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);
}));

También podemos pasar locales para la expresión de evaluación.

allenhwkim
fuente
2

Creo que una de las preguntas originales aquí no fue respondida. Creo que vanilla eval () no se usa porque las aplicaciones angulares no funcionarían como aplicaciones de Chrome, lo que impide explícitamente que eval () se use por razones de seguridad.

Kevin MacDonald
fuente