Angular.js: Comment fonctionne $ eval et pourquoi est-il différent de vanilla eval?

151

J'étais curieux de savoir ce que $scope.$evalvous voyez si souvent dans les directives, alors j'ai vérifié la source et trouvé ce qui suit dans rootScope.js:

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

$parsesemble être défini par ParseProviderin parse.js, qui semble définir une sorte de mini-syntaxe qui lui est propre (le fichier fait 900 lignes).

Mes questions sont:

  1. Que fait exactement $eval? Pourquoi a-t-il besoin de son propre mini-langage d'analyse?

  2. Pourquoi le vieux JavaScript n'est-il pas evalutilisé?

Jonas
la source
13
$ eval évalue une expression angulaire par rapport à / sur la portée actuelle .
Mark Rajcok
4
BTW $parseest incroyablement génial.
Fresheyeball

Réponses:

186

$evalet $parsen'évaluez pas JavaScript; ils évaluent les expressions AngularJS . La documentation liée explique les différences entre les expressions et JavaScript.

Q: Que fait exactement $ eval? Pourquoi a-t-il besoin de son propre mini-langage d'analyse?

À partir de la documentation:

Les expressions sont des extraits de code de type JavaScript qui sont généralement placés dans des liaisons telles que {{expression}}. Les expressions sont traitées par le service $ parse.

C'est un mini-langage de type JavaScript qui limite ce que vous pouvez exécuter (par exemple, aucune instruction de flux de contrôle, à l'exception de l'opérateur ternaire) et ajoute des avantages AngularJS (par exemple des filtres).

Q: Pourquoi le vieux javascript "eval" n'est-il pas utilisé?

Parce qu'il n'évalue pas réellement JavaScript. Comme le disent les documents:

Si ... vous souhaitez exécuter du code JavaScript arbitraire, vous devez en faire une méthode de contrôleur et appeler la méthode. Si vous voulez eval () une expression angulaire de JavaScript, utilisez la méthode $ eval ().

Les documents liés à ci-dessus contiennent beaucoup plus d'informations.

Josh David Miller
la source
Vous avez dit que $ eval n'évaluait pas réellement JavaScript, mais si je fais $ eval ("{id: 'val'}"), j'obtiens un objet JS. (Angular 1.0.8)
Gabriel
7
@Yappli $evaln'évalue pas JavaScript; il évalue les expressions AngularJS, qui sont un peu comme un sous-ensemble plus sûr de JavaScript. "{id: 'val'}"est une expression AngularJS valide et doit renvoyer un objet JS valide. Voir le lien ci-dessus pour la différence entre les expressions et le JS régulier.
Josh David Miller
1
Bonne réponse mais je ne suis pas sûr que "par exemple aucune déclaration de flux de contrôle" soit exact. Vous pouvez faire quelque chose comme ça ... ng-click = "someVal? SomeFunc (someVal): noop" qui est une expression angulaire parfaitement valide
Charlie Martin
@CharlieMartin La documentation dit spécifiquement "aucune instruction de flux de contrôle" , mais votre argument est valide. Cependant, je ne recommanderais certainement pas de faire cela dans un ngClick; ce type de logique appartient presque certainement au contrôleur.
Josh David Miller
1
Intéressant que la documentation dise que comme le support de l'opérateur ternaire a été intentionnellement ajouté ... github.com/angular/angular.js/blob/master/src/ng/ ... Le ng-click n'était qu'un simple exemple et je suis d'accord cette logique devrait être dans un contrôleur, mais je ne vois rien de mal à utiliser un opérateur ternaire dans la notation entre crochets et l'équipe angulaire ne le fait évidemment pas non plus ou ils n'auraient pas ajouté de support pour cela. Je suppose que si une correction devait être apportée, cela devrait se produire dans la documentation avant cette réponse
Charlie Martin
22

Du test,

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

Nous pouvons également passer des sections locales pour l'expression d'évaluation.

allenhwkim
la source
2

Je pense qu'une des questions originales ici n'a pas été répondue. Je crois que vanilla eval () n'est pas utilisé car les applications angulaires ne fonctionneraient pas comme des applications Chrome, ce qui empêche explicitement eval () d'être utilisé pour des raisons de sécurité.

Kevin MacDonald
la source