范围树
当我们需要将单个 html 元素绑定到单个变量时,前面的示例就足够了。
实际上 - 我们需要将许多元素绑定到许多变量:
<span ng-repeat="number in [1,2,3,4,5]">{{number}}</span>
这个 ng-repeat
将 5 个元素绑定到 5 个名为 number
的变量,每个变量都有不同的值!
angular 实现此行为的方式是为每个需要单独变量的元素使用单独的上下文。此上下文称为范围。
每个范围都包含属性,这些属性是绑定到 DOM 的变量,$digest
和 $watch
函数是作为范围的方法实现的。
DOM 是一棵树,变量需要在树的不同级别使用:
<div>
<input ng-model="person.name" />
<span ng-repeat="number in [1,2,3,4,5]">{{number}} {{person.name}}</span>
</div>
但正如我们所看到的,ng-repeat
中变量的上下文(或范围)与其上方的上下文不同。要解决这个问题 - angular 将范围实现为树。
每个范围都有一个子数组,调用它的 $digest
方法将运行它的所有子项的 $digest
方法。
这样 - 在更改输入后 - 为 div 的范围调用 $digest
,然后为其 5 个子节点运行 $digest
- 这将更新其内容。
范围的简单实现可能如下所示:
function $scope(){
this.$children = [];
this.$watches = [];
}
$scope.prototype.$digest = function(){
this.$watches.forEach(function($w){
var val = $w.val();
if($w.prevVal !== val){
$w.callback(val, $w.prevVal);
$w.prevVal = val;
}
});
this.$children.forEach(function(c){
c.$digest();
});
}
$scope.prototype.$watch = function(val, callback){
this.$watches.push({val:val, callback:callback, prevVal: val() })
}