$scope.$watch('foo', fn)
$scope.$watch(function() {return $scope.foo}, fn)
$scope.$watch(obj.prop, fn)
$scope.$watch(function() {return obj.prop}, fn)
具有非范围对象的对产生了不同的结果,因为在obj.prop更改时,前一个表达式没有执行。但为什么呢?
答案 0 :(得分:1)
$scope.$watch('foo', fn)
这将使用$parse
服务来观看$scope.foo
的值,并将旧值与新值进行比较。
$scope.$watch(function() {return $scope.foo}, fn)
这与第一个相同,但使用lambda。 function() {return $scope.foo}
将在每个$digest
上执行,旧return
值将与return
新值进行比较。
$scope.$watch(obj.prop, fn)
这个很奇怪而且不推荐,因为它的行为完全取决于obj.prop
的类型。例如,如果obj.prop === "foo"
,那么它将与$scope.$watch('foo', fn)
相同。如果obj.prop === function(){ return Math.random(); }
那么你有一个奇怪的事情。如果对于$watch
的更改,您希望角度到obj.prop
obj.prop
的值,则不会以这种方式工作。
$scope.$watch(function() {return obj.prop}, fn)
这个与$scope.$watch(function() {return $scope.foo}, fn)
相同,因为 angular 将运行lambda function() {return obj.prop}
每个$digest
。旧return
值将与新值进行比较。你在这里所拥有的最终是以正确的方式观看$scope
上没有的东西。它会监视obj.prop
的更改(因为它的return
值。)
答案 1 :(得分:0)
我查看了代码,这就是它失败的原因:
$watch: function(watchExp, listener, objectEquality) {
var get = $parse(watchExp);
if (get.$$watchDelegate) {
return get.$$watchDelegate(this, listener, objectEquality, get);
}
var scope = this,
array = scope.$$watchers,
watcher = {
fn: listener,
last: initWatchVal,
get: get,
exp: watchExp,
eq: !!objectEquality
};
lastDirtyWatch = null;
if (!isFunction(listener)) {
watcher.fn = noop;
}
if (!array) {
array = scope.$$watchers = [];
}
// we use unshift since we use a while loop in $digest for speed.
// the while loop reads in reverse order.
array.unshift(watcher);
return function deregisterWatch() {
arrayRemove(array, watcher);
lastDirtyWatch = null;
};
},
因此,当执行比较时,查看是否(value = watch.get(current)) !== (last = watch.last)
,它基本上调用get
第二行中的$watch
并将其新值与存储的值进行比较。要知道get
是什么,我看了$parse
:
return function $parse(exp, interceptorFn) {
var parsedExpression, oneTime, cacheKey;
switch (typeof exp) {
case 'string':
cacheKey = exp = exp.trim();
parsedExpression = cache[cacheKey];
if (!parsedExpression) {
if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
oneTime = true;
exp = exp.substring(2);
}
var lexer = new Lexer($parseOptions);
var parser = new Parser(lexer, $filter, $parseOptions);
parsedExpression = parser.parse(exp);
if (parsedExpression.constant) {
parsedExpression.$$watchDelegate = constantWatchDelegate;
} else if (oneTime) {
//oneTime is not part of the exp passed to the Parser so we may have to
//wrap the parsedExpression before adding a $$watchDelegate
parsedExpression = wrapSharedExpression(parsedExpression);
parsedExpression.$$watchDelegate = parsedExpression.literal ?
oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
} else if (parsedExpression.inputs) {
parsedExpression.$$watchDelegate = inputsWatchDelegate;
}
cache[cacheKey] = parsedExpression;
}
return addInterceptor(parsedExpression, interceptorFn);
case 'function':
return addInterceptor(exp, interceptorFn);
default:
return addInterceptor(noop, interceptorFn);
}
};
基本上,观察表达式的类型有不同的情况。它有string
,function
和default
。
如果我看到的表达式obj.prop
被评估为:
string
,例如'foo'
,它将被视为$scope.foo
案件。function
,它会在没有第二个参数的情况下传递到$parse(watchExp)
,而是按addInterceptor
原样返回,并在每个$digest
内执行,其返回值作为要比较的值。addInterceptor(noop, interceptorFn)
将在没有interceptorFn
的情况下处理。由于noop
只是一个空的角度函数,因此这个函数不会做任何事情。因此,如果我想检查obj.prop
不属于$ scope的一部分,我应该使用返回值路由的函数$scope.$watch(function() {return obj.prop}, fn)
。