参考资料:
angularJs权威指南 第23章
angularJs 核心源码浅析 http://dengkunli.com/angular-source-code-series-one/?utm_source=tuicool&utm_medium=referral
根据上述的文章和连接,已经很详细的讲述了相关问题。以下是自己的简单理解:
核心原理:AngularJs双向数据绑定是基于“脏值检测”($digest循环中提供)的功能实现的。即是指当且仅当“新值”与“旧值”不相等时执行此功能代码。
$digest中脏值检测代码如下:
do { // "traverse the scopes" loop
if ((watchers = current.$$watchers)) {
// process our watches
length = watchers.length;
while (length--) {
try {
watch = watchers[length];
// Most common watches are on primitives, in which case we can short
// circuit it with === operator, only when === fails do we use .equals
if (watch) {
get = watch.get;
if ((value = get(current)) !== (last = watch.last) &&
!(watch.eq
? equals(value, last)
: (typeof value === 'number' && typeof last === 'number'
&& isNaN(value) && isNaN(last)))) {
dirty = true;
lastDirtyWatch = watch;
watch.last = watch.eq ? copy(value, null) : value;
fn = watch.fn;
fn(value, ((last === initWatchVal) ? value : last), current);
if (ttl < 5) {
logIdx = 4 - ttl;
if (!watchLog[logIdx]) watchLog[logIdx] = [];
watchLog[logIdx].push({
msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
newVal: value,
oldVal: last
});
}
} else if (watch === lastDirtyWatch) {
// If the most recently dirty watcher is now clean, short circuit since the remaining watchers
// have already been tested.
dirty = false;
break traverseScopesLoop;
}
}
} catch (e) {
$exceptionHandler(e);
}
}
}
// Insanity Warning: scope depth-first traversal
// yes, this code is a bit crazy, but it works and we have tests to prove it!
// this piece should be kept in sync with the traversal in $broadcast
if (!(next = ((current.$$watchersCount && current.$$childHead) ||
(current !== target && current.$$nextSibling)))) {
while (current !== target && !(next = current.$$nextSibling)) {
current = current.$parent;
}
}
} while ((current = next));
那么,我们的问题来了。AngularJS是怎么确保动态监听数据的变化的呢:首先再其自己内部的指令后调用了$apply()。再通过其调用$digest()(注意在此过程中调用的是$rootScope作用域上的)。
$$Phase:AngularJS内部的状态标志位,并且$scope.$$Phase返回字符串以标识“$apply” “$digest”及“”状态。
为防止与您的代码意外的名称冲突,AngularJS将公共对象的$名称与私有对象的名称前缀$$。请不要在代码中使用$或$$前缀。