I was curious about the $scope.$eval
you so often see in directives, so I checked out the source and found the following in rootScope.js
:
$eval: function(expr, locals) {
return $parse(expr)(this, locals);
},
$parse
appears to be defined by ParseProvider
in parse.js
, which appears to define some kind of mini-syntax of its own (the file is 900 lines long).
My questions are:
What exactly is $eval
doing? Why does it need its own mini parsing language?
Why isn't plain old JavaScript eval
being used?
The AngularJS $eval method is used to executes the AngularJS expression on the current scope and returns the result. In AngularJS, expressions are similar to JavaScript code snippets that are usually placed in bindings such as {{ expression }}.
JavaScript eval() The eval() method evaluates or executes an argument. If the argument is an expression, eval() evaluates the expression. If the argument is one or more JavaScript statements, eval() executes the statements.
eval() is also slower than the alternatives, since it has to invoke the JavaScript interpreter, while many other constructs are optimized by modern JS engines. Additionally, modern JavaScript interpreters convert JavaScript to machine code. This means that any concept of variable naming gets obliterated.
$eval
and $parse
don't evaluate JavaScript; they evaluate AngularJS expressions. The linked documentation explains the differences between expressions and JavaScript.
Q: What exactly is $eval doing? Why does it need its own mini parsing language?
From the docs:
Expressions are JavaScript-like code snippets that are usually placed in bindings such as {{ expression }}. Expressions are processed by $parse service.
It's a JavaScript-like mini-language that limits what you can run (e.g. no control flow statements, excepting the ternary operator) as well as adds some AngularJS goodness (e.g. filters).
Q: Why isn't plain old javascript "eval" being used?
Because it's not actually evaluating JavaScript. As the docs say:
If ... you do want to run arbitrary JavaScript code, you should make it a controller method and call the method. If you want to eval() an angular expression from JavaScript, use the $eval() method.
The docs linked to above have a lot more information.
From the 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);
}));
We also can pass locals for evaluation expression.
I think one of the original questions here was not answered. I believe that vanilla eval() is not used because then angular apps would not work as Chrome apps, which explicitly prevent eval() from being used for security reasons.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With