Angular.js: Как работает $ eval и чем он отличается от vanilla eval?

151

Мне было любопытно, что $scope.$evalвы так часто видите в директивах, поэтому я проверил источник и нашел следующее в rootScope.js:

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

$parseпо-видимому, определяется с помощью ParseProviderin parse.js, который, по-видимому, определяет некоторый собственный мини-синтаксис (длина файла составляет 900 строк).

Мои вопросы:

  1. Что именно $evalделает? Зачем ему нужен собственный мини-язык синтаксического анализа?

  2. Почему не используется старый старый JavaScript eval?

Иона
источник
13
$ eval оценивает угловое выражение против / в текущей области .
Марк Райкок
4
Кстати $parse, безумно здорово.
Fresheyeball

Ответы:

186

$evalи $parseне оценивайте JavaScript; они оценивают выражения AngularJS . Связанная документация объясняет различия между выражениями и JavaScript.

Q: Что именно делает $ eval? Зачем ему нужен собственный мини-язык синтаксического анализа?

Из документов:

Выражения - это фрагменты кода в стиле JavaScript, которые обычно помещаются в привязки, например {{expression}}. Выражения обрабатываются сервисом $ parse.

Это JavaScript-подобный мини-язык, который ограничивает то, что вы можете запускать (например, нет операторов потока управления, исключая троичный оператор), а также добавляет некоторые преимущества AngularJS (например, фильтры).

В: Почему не используется простой старый javascript «eval»?

Потому что это на самом деле не оценка JavaScript. Как говорят в документах:

Если ... вы хотите запустить произвольный код JavaScript, вы должны сделать его методом контроллера и вызвать метод. Если вы хотите eval () угловое выражение из JavaScript, используйте метод $ eval ().

Документы, ссылки на которые приведены выше, содержат гораздо больше информации.

Джош Дэвид Миллер
источник
Вы сказали, что $ eval на самом деле не оценивает JavaScript, но если я сделаю $ eval ("{id: 'val'}"), я получу объект JS. (Angular 1.0.8)
Габриэль
7
@Yappli $evalне оценивает JavaScript; он оценивает выражения AngularJS, которые вроде как более безопасное подмножество JavaScript. "{id: 'val'}"является допустимым выражением AngularJS и должно возвращать действительный объект JS. См. Ссылку выше для различия между выражениями и обычным JS.
Джош Дэвид Миллер
1
Хороший ответ, но я не уверен, что «например, нет операторов потока управления» является точным. Вы можете сделать что-то вроде этого ... ng-click = "someVal? SomeFunc (someVal): noop", которое является совершенно допустимым угловым выражением
Чарли Мартин,
@CharlieMartin В документации конкретно говорится «нет операторов потока управления» , но ваша точка зрения верна. Однако я определенно не рекомендовал бы делать это в ngClick; такая логика почти наверняка принадлежит контроллеру.
Джош Дэвид Миллер
1
Интересно, что в документах говорится, что в качестве преднамеренно добавлена ​​поддержка троичного оператора ... github.com/angular/angular.js/blob/master/src/ng/… ng-click был всего лишь простым примером, и я согласен эта логика должна быть в контроллере, но я не вижу ничего плохого в использовании троичного оператора в скобочных обозначениях, и угловая команда, очевидно, тоже этого не делает, иначе они бы не добавили поддержку этого. Я полагаю, что если будет сделано исправление, то это должно произойти в документации до этого ответа
Чарли Мартин
22

Из теста,

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

Мы также можем передать локальные выражения для выражения оценки.

allenhwkim
источник
2

Я думаю, что один из оригинальных вопросов здесь не был дан ответ. Я считаю, что vanilla eval () не используется, потому что тогда угловые приложения не будут работать как приложения Chrome, которые явно не позволяют использовать eval () по соображениям безопасности.

Кевин Макдональд
источник