这几天,根据buddy指定的任务,要分享一点angular JS的东西。对于一个在前端属于纯新手的我来说,Javascript都还是一知半解,要想直接上手angular JS,遇到的阻力还真是不少。不过我相信,只要下功夫,即使是反人类的设计也不是什么大的问题。
     Okay,废话不多说。为了弄明白angular JS为何物,我先是从Scope开始。那么什么是Scope呢?借用官方文档的一段话:

“scope is an object that refers to the application model. It is an execution context for expressions. Scopes are arranged in hierarchical structure which mimic the DOM structure of the application. Scopes can watch expressions and propagate events.”

  看完后,类比到其他的编程语言上,感觉Scope就像是Data Model的作用域一样,为Expressions的执行提供上下文,暂且先这么理解吧。

  • Scope的特性

  接下来,看看Scope有哪些特性呢?

  1. Scope提供$watch方法监视Model的变化。
  2. Scope提供$apply方法传播Model的变化。
  3. Scope可以继承,用来隔离不同的application components和属性访问权限。
  4. Scope为Expressions的计算提供上下文。

对于这四点特性,因为我之前学习过ActionScript、C++、Java,所以第一、三、四点不难理解,唯独第二点感觉有点云里雾里。本着打破沙锅问到底的原则,我还是通过Google搜到了一些东西。对于有经验的老手,板砖请轻拍!

  • 源起Javascript

首先,乍一看,scope.apply()似乎就是一个使得bindings得到更新的普普通通的方法。但稍微多想一点,为什么我们需要它?一般在什么时候用它呢?用弄明白这两个问题,还得从Javascript说起。在Javascript代码里,都是按照一定顺序来执行的,当轮到一个代码片段执行的时候,浏览器就只会去执行当前的片段,不会做任何其他的事情。所以有时候一些做得不是很好的网页,当点击了某个东西之后会卡住,Javascript的工作方式就是会导致这一现象原因之一!下面我们有一段代码来感受一下:

  1. var button = document.getElementById('clickMe');
  2. function buttonClicked () {
  3. alert('the button was clicked');
  4. }
  5. button.addEventListener('click', buttonClicked);
  6. function timerComplete () {
  7. alert('timer complete');
  8. }
  9. setTimeout(timerComplete, 5000);

当加载Javascript代码时,先先找一个一个id叫“clickMe”的按钮,然后添加一个监听器,然后设置超时。等待5秒,会弹出一个对话框。如果刷新页面并立即点击clickMe按钮,会弹出一个对话框,如果你不点击OK,timerComplete函数永远没有机会执行。

  • 如何更新bindings

好了,扯了一些看似不相关的东西之后,我们回归正题。angular JS是怎么知道什么时候数据的变化和页面需要更新的呢?代码需要知道什么时候数据被修改了,但是现在又没有一种方法直接去通知说某个对象上的数据变了(尽管ECMAScript 5正在尝试解决这一问题,但也还是处于实验阶段)。而目前比较主流的策略有以下有两种解决方案。一种是需要用特殊的对象,让所有的数据都只能通过调用对象的方法设置,而不是直接通过property指定。这样的话,所有的修改就可以被记录下来了,就知道什么时候页面需要更新了。这样做的弊端就是我们必须去继承一个特殊的对象。对于赋值也只能通过object.set('key', 'value')而不是object.key=value的方式。在框架中,像EmberJSKnockoutJS就是这么干的(虽然我都没接触过——囧)。另一种就是angular JS采用的方式,在每一次Javascript代码执行序列执行结束后都去检查是否有数据的改变。这看起来似乎并不高效,甚至严重影响性能。但是angular JS采用了一些比较巧妙的手段解决了这个问题(还没研究过,目前尚不明确)。这么做的好处就是,我们可以随便使用任意对象,对于赋值方式也没有限制,而且对于数据的改变也能觉察到。
     对于angular JS采取的这种解决方案,我们关心的是什么时候数据发生了变化,而这也正是scope.apply()派上用场的地方。对于检查绑定的数据到底有没有发生变化,实际上是由scope.digest()完成的,但是我们几乎从来就没有直接调用过这个方法,而是调用scope.apply()方法,是因为在scope.apply()方法里面,它会去调用scope.digest()方法。scope.apply()方法带一个函数或者一个表达式,然后执行它,最后调用scope.digest()方法去更新bindings或者watchers。

  • 什么时候用$apply()

还是那个问题,那我们到底什么时候需要去调用apply()方法呢?情况非常少,实际上几乎我们所有的代码都包在scope.apply()里面,像ng−click,controller的初始化,http的回调函数等。在这些情况下,我们不需要自己调用,实际上我们也不能自己调用,否则在apply()方法里面再调用apply()方法会抛出错误。如果我们需要在一个新的执行序列中运行代码时才真正需要用到它,而且当且仅当这个新的执行序列不是被angular JS的库的方法创建的,这个时候我们需要将代码用scope.apply()包起来。下面用一个例子解释:
[HTML]

  1. <div ng:app ng-controller="Ctrl">{{message}}</div>

[Javascript]

  1. functionCtrl($scope) {
  2. $scope.message ="Waiting 2000ms for update";
  3. setTimeout(function () {
  4.   $scope.message ="Timeout called!";
  5. // AngularJS unaware of update to $scope
  6. }, 2000);
    }

上面的代码执行后页面上会显示:Waiting 2000ms for update。显然数据的更新没有被angular JS觉察到。
     接下来,我们将Javascript的代码稍作修改,用scope.apply()包起来。
[Javascript]

  1. functionCtrl($scope) {
  2. $scope.message ="Waiting 2000ms for update";
  3. setTimeout(function () {
  4.   $scope.$apply(function () {
  5.   $scope.message ="Timeout called!";
  6. });
  7. }, 2000);
    }

这次与之前不同的是,页面上先会显示:Waiting 2000ms for update,等待2秒后内容会被更改为:Timeout called! 。显然数据的更新被angular JS觉察到了。
     NOTE:我们不应该这样做,而是用angular JS提供的timeout方法,这样它就会被自动用apply方法包起来了。

  • 科学是把双刃剑

最后,我们再来瞅一眼scope.apply()和scope.apply(function)方法吧!虽然angular JS为我们做了很多事情,但是我们也因此丢失了一些机会。从下面的伪代码一看便知:

  1. function$apply(expr) {
  2.   try {
  3.     return$eval(expr);
  4.   } catch(e) {
  5.     $exceptionHandler(e);
  6.   } finally {
  7.     $root.$digest();
  8.   }
  9. }

  它会捕获所有的异常并且不会再抛出来,最后都会调用$digest()方法。

  • 总结一下

  $apply()方法可以在angular框架之外执行angular JS的表达式,例如:DOM事件、setTimeout、XHR或其他第三方的库。这仅仅是个开始,水还有很深,欢迎大家一起来deep dive!

===================================================================

  • Reference

   原文:http://jimhoskins.com/2012/12/17/angularjs-and-apply.html

  • 【题外话】

If you are assigning a string containing a . char, you will need to use the $apply(fn) method or you will get an error.
Example:

  1. var imagename = "myimage.png";
  2. $scope.$apply($scope.image = imagename);

The code above will throw an error because Angular will interpret the string as an object. Using the function method this does not happen.
Example:

  1. $scope.$apply(function () {
      $scope.image = imagename;
  2. });

来源:http://www.cnblogs.com/penghongwei/p/3398361.html

[转]angular之$apply()方法的更多相关文章

  1. angularJS之$watch、$digest和$apply方法

    最近项目上使用了比较多的angular JS,一直都对它感觉比较陌生,总觉得有点反直觉,这段时间,准备下定决心弄明白,这个框架到底是怎么一回事,以及它的工作原理,生命周期……一点一点的啃完它吧.首先, ...

  2. angularJS之$apply()方法

    这几天,根据buddy指定的任务,要分享一点angular JS的东西.对于一个在前端属于纯新手的我来说,Javascript都还是一知半解,要想直接上手angular JS,遇到的阻力还真是不少.不 ...

  3. angular之$watch方法详解

    在$apply方法中提到过脏检查,首先apply方法会触发evel方法,当evel方法解析成功后,会去触发digest方法,digest方法会触发watch方法. (1)$watch简介 在diges ...

  4. angularJS中$apply()方法详解

    这篇文章主要介绍了angularJS中$apply()方法详解,需要的朋友可以参考下   对于一个在前端属于纯新手的我来说,Javascript都还是一知半解,要想直接上手angular JS,遇到的 ...

  5. angularJS $scope的$apply方法实现model刷新

    控制器内,$scope有个$apply方法,可以代码更改model并同步更新页面.通常,控制器内的方法执行完毕后仅会自动刷新一次页面展示,使用$apply方法即可在想刷新页面时就刷新.如本例,这个方法 ...

  6. 深入了解angularjs中的$digest与$apply方法,从区别聊到使用优化

     壹 ❀ 引 如果有人问,在angularjs中修改模型数据为何视图会同步更新呢,我想大多数人一定会回答脏检查(Dirty Checking)相关概念.没错,在angularjs中作用域(scope) ...

  7. JS中 call() 与apply 方法

    1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象. 说明: call ...

  8. JavaScript学习笔记(1))——————call,apply方法

    学习前端也有一段时间了,但是效果甚微.利用时间不够充分,虽然是利用工作之余来学习.但是这不能成为我的借口. 今天学习了(其实看了很多遍)call apply方法. function abc(a,b){ ...

  9. angularjs $scope.$apply 方法详解

    myApp.controller('firstController',function($scope,$interval){ $scope.date = new Date(); setInterval ...

随机推荐

  1. Mycat实现Mysql数据库读写分离

    Linux和Windows环境下搭建Mycat数据读写分离 前提需要:1.服务器装有JVM虚拟机,就是JDK.2.两个Mysql数据库已经实现主从复制,参考:https://www.cnblogs.c ...

  2. 明远imx6

    http://pan.baidu.com/s/1ntsrQtF#path=%252FMY-I.MX6%2520V2.5 nkuc tftpboot 0x10800000 uImage.ramdisk ...

  3. linux alsa pcm(此pcm非硬件pcm接口)

    转:https://blog.csdn.net/crycheng/article/details/7095899 CODEC :音频芯片的控制,比如静音.打开(关闭)ADC(DAC).设置ADC(DA ...

  4. JSON.parse和JSON.stringify的作用

    //JSON.parse将字符串格式json转化为json对象 var str='{"name":"lingling","age":&quo ...

  5. Java Collection API

    在 Java2中,有一套设计优良的接口和类组成了Java集合框架Collection,使程序员操作成批的数据或对象元素极为方便.这些接口和类有很多对抽象数据类型操作的API,而这是我们常用的且在数据结 ...

  6. 一个gpio 不受控制的bug

    前几天调试一个flash灯的驱动程序,这可ic 有两个控制pin, 一个叫en1 一个叫en2, 根据spec的说明,不同的组合将产生不同的输出电流.但我发现,那个en1 这个pin 死活是拉不高的, ...

  7. 算法总结之 将单链表的每K个节点之间逆序

    给定一个单链表的表头节点head,实现一个调整单链表的函数,是的每k个节点之间逆序,如果最后不够k个节点一组,则不调整最后几个节点 思路: 如果k的值小于2,不调整.k<1 没有意义,k==1代 ...

  8. Shell中数学计算/运算

    shell中的赋值和操作默认都是字符串处理. 1)使用let(只能进行整数运算)var=1let "var+=1"echo $var输出结果为2 注意:a)let几乎支持所有的运算 ...

  9. C#反射第一天

    [转]C#反射   反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类.结构.委托.接口和枚举等)的成员,包括方法.属性.事件,以及构造函数等. ...

  10. Linux嵌入式 -- 内核 - 内核链表

    1. linux内核链表 链表数据结构的定义: struct list_head  {  struct list_head *next, *prev;  };  list_head结构包含两个指向li ...