# $apply方法、$digest方法

## $apply

* $scope.$apply(expression)
* $apply()方法可以在angular框架之外执行angular JS的表达式，例如：DOM事件、setTimeout、XHR或其他第三方的库。

### angular是怎么知道变量发生了改变

要知道一个变量变了，方法不外乎两种

1. 能通过固定的接口才能改变变量的值，比如说只能通过 set() 设置变量的值，set被调用时比较一下就知道了。

   这中方法的缺点洗是写法繁琐
2. 脏检查，将原对象复制一份快照，在某个时间，比较现在对象与快照的值，如果不一样就表明发生变化，这个策略要保留两份变量，而且要遍历对象，比较每个属性，这样会有一定性能问题

**angular的策略:angular的实现是使用脏检查**

1. 不会脏检查所有的对象，当对象被绑定到html中，这个对象添加为检查对象（watcher）。
2. 不会脏检查所有的属性，同样当属性被绑定后，这个属性会被列为检查的属性。

在angular程序初始化时，会将绑定的对象的属性添加为监听对象（watcher），也就是说一个对象绑定了N个属性，就会添加N个watcher。

#### 什么时候去脏检查

angular 所系统的方法中都会触发比较事件，比如：controller 初始化的时候，所有以ng-开头的事件执行后，都会触发脏检查。

#### 手动触发脏检查

* $apply仅仅只是进⼊入angular context ,然后通过$digest去触发脏检查
* $apply如果不给参数的话，会检查该$scope⾥里的所有监听的属性，推荐给上参数

**例子**

index.html

```markup
<div ng-app="myApp">

        <div ng-controller="firstController">
            {{date}}
        </div>
    </div>
    <script src="//cdn.bootcss.com/angular.js/1.4.8/angular.js"></script>
    <script type="text/javascript" src="app/index.js"></script>
```

app/index.js

```javascript
app.controller('firstController', function($scope){

    $scope.date = new Date();

//    setInterval(function(){
//        // 这里虽然变 但是并没有触发 脏检查
//        $scope.date = new Date();
//
//    },1000)

    setInterval(function(){
        $scope.$apply(function(){
            $scope.date = new Date();
            //....会去触发脏检查
        })
    },1000)


    // 触发一次脏检查
});
```

注意如下代码，虽然打印出来每秒将会触发时间，但是没有触发脏检查，不会触发页面上的改变。

```javascript
setInterval(function(){
    // 这里虽然变 但是并没有触发 脏检查
    $scope.date = new Date();
    console.log(new Date());

},1000)
```

## $digest

* 所属的scope和其所有子scope的脏检查，脏检查又会触发$watch()，整个Angular双向绑定机制就活了起来\~
* 不建议直接调用$digest()，而应该使用$apply()，$apply其实不能把信直接送给$digest，之间还有$eval门卫把关，如果$apply带的表达式不合法，$eval会把错误送交$exceptionHandler，合法才触发digest，所以更安全。

## 简单理解过程

触发$apply,执行完，执行脏检查，检查每个$scope下的属性是否有变化，有变化的话，触发watch监听事件，页面上的对应值value和绑定的model值都会跟着改变。

并不是所有的时间都需要$apply.当自定义的地方才需要。
