Scope
A clean way to listen for changes on JavaScript expressions.
Install
$ component install expressionjs/scope
Overview
The scope is an object that takes some arbitrary JavaScript object and a set of JavaScript expressions, and notifies you when any one of those expressions need to be re-evaluated.
How does it work?
Expressions have "paths"
It boils down to the fact that an expression contains a set of properties, or paths. For example, you might have expressions like this:
count > 10isLoggedIn ? "Log out" : "Log in"usernameuseraddresscity
Each of those expressions contain a set of paths (the top-level ones you can think of as just "properties"):
'count' 'loggedIn' 'user' 'user.name' 'user' 'user.address' 'user.address.city'
Some expressions can also have dynamic properties:
userattr
which is basically this:
'user' 'attr' { return thisdatauserattr }
A scope is a set of expressions
When you define a scope, you are giving it expressions:
var scope = ;var a = 'count > 10';var b = 'isLoggedIn ? "Log out" : "Log in"';a;b;
So now, the scope has 2 expressions, each which have their own sets of paths. This means a scope knows the set of all paths for all it's expressions. This makes it easy to compute which expressions should be updated when one path changes.
An expression is a function and a set of paths
Each of those expressions just has a set of paths, and a compiled function to get or set the value of the expression:
var exp = 'count > 10';exppaths; // [ 'count' ]
An expression is evaluated in reference to a scope
In your everyday JavaScript, you are creating expressions that are in a scope, such as a function scope:
{ var count = 5; { return count > 10; } return ;}
Each function above defines a scope, so the expression count > 10
is inside the second scope, but the value of count
comes from the first scope. So basically, you have a tree of scopes, and expressions that are interpreted in reference to those scopes.
In the same way, the scope
object in this repo is used to evaluate expressions. So basically, we have (to some degree) reimplemented scope/expression functionality in JavaScript.
Why did we do this?
Watching expressions for changes
In many HTML template engines, one of the goal is to watch some data for changes, and update the DOM when that data changes. Long-story short, there is no clean/easy way to do this in JavaScript without introducing a bunch of magic.
So what we have done is create essentially a data structure for you that will tell you if your expressions need to be re-evaluated, without too much magic (such as overriding properties with getters/setters). That's what this scope
is; a container for expressions, that will notify you when a specific expression needs to be re-evaluated.
This is a much simpler way of managing it that manually controlling observers, or having to extend custom objects like with Ember.
A base for template engines
This component is a low-level foundation for template engines to build on top of. It makes it so you can get the full power of understanding and evaluating custom expressions (not just JavaScript expressions, you can also write your own using custom grammars!).
As a reference implementation, we have creating templatejs on top of this, our ideal template engine.
Usage
On a day-to-day basis, you probably won't ever need to go down to the level of understanding the scope. Things like template engines will build simpler abstractions on top of it.
But in case you're interested, here is how you use it:
var Scope = ;var Expression = ; // initialize your expressionsvar a = 'isLoggedIn && count > 10';var b = 'isLoggedIn ? "Log out" : "Log in"'; // initialize your scopevar scope = ; // bind expressions to scopea;b; // arbitrary datavar data = count: 20 loggedIn: false; // bind the data your scopescope; // watch for changes on an expressiona; b; // set the value of a pathscope;// a: true// b: "Log out"scope;// a: false// b: "Log in"
Scopes can also be nested:
var scope = ;var child = scope;var grand = child;
If you just want to re-execute all your expressions, then rebind your data:
scope;
Notes
License
MIT