angularjs中的$watch

    在使用AngulaJS编写应用时,我们经常需要做的一件事情就是对模型中的变量进行监视,并对其发生的变化做出相应的回应。AngularJS为我们提供了一个非常方便的$watch方法,它可以帮助我们在每个scope中监视其中的变量。下面是一个非常简单的例子:

<html ng-app='myApp'>
    <head>
        <meta charset="UTF-8">
        <script src='../lib/angular.js'></script>
    </head>
    <body>
        <input ng-model='name' type='text'/>
        <div>change count: {{count}}</div>
        <script>
            angular.module('myApp',[])
                         .run(['$rootScope',function($rootScope){
                                $rootScope.count = 0;
                                $rootScope.name = 'hcc';
                                $rootScope.$watch('name',function(){
                                    $rootScope.count++;
                                })
                         }]);
        </script>
    </body>
    </html>

  上面的代码很简单,它用$watch来对$rootScope中的name进行监视,并在它发生变化的时候将$rootScope中的count属性增加1。因此,每当我们对name进行一次修改时,下面显示的count数字就会增加1。 

  在AngularJS内部,每当我们对ng-model绑定的name属性进行一次修改,AngularJS内部的$digest就会运行一次,并在运行结束之后检查我们使用$watch来监视的东西,如果和进行上一次$digest之前相比有了变化,则执行我们在其中绑定的处理函数。

   然而,我们在实际运用中常常不只是对一个原始类型的属性进行监视,还可能对集合进行监视,如果你还记得Javascript中的五种基本类型(number, boolean, null, undefined, string)。对于原始类型,如果我们使用了一个赋值操作,则这个原始类型变量会“真正的”被进行一次复制,然而对于引用类型,在进行赋值时,仅仅时将赋值的变量指向了这个引用类型。在AngularJS的$watch方法中,对两者的操作也有不同之处。原始类型,就像我们上面例子中提到的$rootScope,没有什么特别之处,然而如果要对一个引用类型,尤其是在实际运用中常见的对象数组进行监视时,情况就不一样了。我们来看下面的例子:

<html ng-app='myApp'>
   <head>
        <meta charset="UTF-8">
        <script src='../lib/angular.js'></script>
    </head>
    <body>
        <div hg-repeat='item in items'>
            <input ng-model='item.a'/><span>{{item.a}}</span>
        </div>
        <div>change count: {{count}}</div>
        <script>
            angular.module('myApp',[])
                         .run(['$rootScope',function($rootScope){
                                $rootScope.count = 0;
                                $rootScope.items = [
                                    { "a": 1 },
                                    { "a": 2 },
                                    { "a": 3 },
                                    { "a": 4 }
                                ]
                                $rootScope.$watch('items',function(){
                                    $rootScope.count++;
                                })
                         }]);
        </script>
    </body>
    </html>

通过运行上面的代码,我们发现count的值始终是1,难道没有检测到吗?其实$watch()还有第三个参数,默认是false我们称这种监视叫做“引用监视”。即“reference watch”,它的意思是只要监视的对象引用没有发生变化,就不算它发生了变化。具体来说,在上面的例子中,只要是items的引用没有发生变化,就算items中的一些属性发生了变化,$watch也不与理会,那什么时候才能检测到这种属性变化呢?

    如果我们将$watch的第三个变量设置为true,那么此时我们进行的监视叫做“全等监视”,原词是“equality watch”。如果增加或者删除,$watch将会检测到。

    既然“全等监视”那么功能那么好用,为什么不经常使用呢?那是因为它的性能问题,它在运行时需要先遍历整个监视对象,然后在每次$digest之前使用angular.copy()将整个对象深拷贝一遍然后在运行之后用angular.equal()将前后的对象进行对比,上面的例子中因为items比较简单,因此可能性能上不会有什么差别,但是到了实际生产时,我们要面对的数据千千万万,可能因为全等监视这一个设置就会消耗大量的资源。

   除了上面提到的两种方式之外,在angular 1.1.4版本之后,添加了一个$watchCollection()方法来针对数组(也就是集合)进行监视,它的性能介于全等监视和引用监视二者之间,即它并不会对数组中每一项的属性进行监视,但是可以对数组的项目的增减做出反应。比如还是上面的例子:

                    $rootScope.items = [
                            { "a": 1 },
                            { "a": 2 },
                            { "a": 3 },
                            { "a": 4 }
                            ]
                            $rootScope.$watchCollection('items',function()                            {
                                $rootScope.count++;
                            })
                     }]);

对集合的操作,推荐使用这种方式。



你可能感兴趣的:(AngularJS,apply,digest,watch)