angular之中,$state,$watch,$scope,$rootScope
分别是什么?
1.背景介绍
在平时的编码中,我们总会想着有什么方法能够简化我们的工作流程,让我们只专心于业务逻辑和数据的处理,而angularjs
就为我们程序员实现了这一点。AngularJS有着诸多特性,最为核心的是:MVC、模块化、自动化双向数据绑定、语义化标签、依赖注入等等。下面,我们将要讨论的就是angularJS里面的 s c o p e scope scoperootScope w a t c h 和 watch和 watch和state
2.知识剖析
作用域
我们可以把angularJs里面的作用域看做为一个容器,在控制器中我们可以访问这个容器我们可以往这个容器中放入一些模型数据,在视图中我们可以通过表达式将数据展示给用户。作用域是应用在HTML(视图)和JavaScript(控制器)之间的纽带,他是一个对象,有可用的方法和属性,可应用在视图和控制器上。
r o o t S c o p e 与 rootScope与 rootScope与scope
【1】当angularJS遇到ng-app指令的时候就会自动生成一个名为 r o o t S c o p e 的 作 用 域 , 该 作 用 域 就 是 就 是 a n g u l a r J S 的 根 作 用 域 。 rootScope的作用域,该作用域就是就是angularJS的根作用域。 rootScope的作用域,该作用域就是就是angularJS的根作用域。rootScope就相当于一个全局作用域,所以我们保存在其中的东西是全局性的,在任一controller之中都能够使用
【2】当angularJS遇到controller或者一些自定义指令的时候也会自动的生成一个名为$scope的作用域scope是html和单个controller之间的桥梁,数据绑定就靠他了。
【3】 s c o p e 都 是 scope都是 scope都是rootScope的子作用域。
$watch
相信使用过angularjs的同学都知道,ng中有个比较重要的特点,叫做双向绑定,那么这个双向绑定是如何实现的呢?当我们在对绑定的name属性进行修改的时候,angular内部的 d i g e s t 循 环 级 会 执 行 一 次 , 他 执 行 的 内 容 是 检 查 我 们 的 digest循环级会执行一次,他执行的内容是检查我们的 digest循环级会执行一次,他执行的内容是检查我们的scope作用域的内容与上次执行 d i g e s t 循 环 的 时 候 是 否 有 变 化 , 若 有 变 化 就 执 行 digest循环的时候是否有变化,若有变化就执行 digest循环的时候是否有变化,若有变化就执行watch()方法绑定的处理函数。从而达到了监听作用域属性的效果。
$watch(watchExpression,listener,objectEquality);
watchExpression,需要监控的表达式
listener,处理函数,函数参数如下function(newValue,oldValue,scope)
objectEquality,是否深度监听,如果设置为true,它告诉Angular检查所监控的对象中每一个属性的变化.如果你希望监控数组的个别元素或者对象的属性而不是一个普通的值,那么你应该使用它
$state
在ajax技术发展普及之后,因为其不会留下历史记录方便浏览器访问和对于seo不友好的特点,一个新技术应运而生:路由,$state就是路由中的一项服务。
$state.go()
s t a t e . g o ( ) 方 法 可 以 产 生 与 a 链 接 一 样 的 效 果 , 可 以 将 此 方 法 绑 定 给 一 个 b u t t o n 按 钮 , 然 后 在 按 钮 的 点 击 事 件 中 国 执 行 state.go()方法可以产生与a链接一样的效果,可以将此方法绑定给一个button按钮,然后在按钮的点击事件中国执行 state.go()方法可以产生与a链接一样的效果,可以将此方法绑定给一个button按钮,然后在按钮的点击事件中国执行state.go(),就可以跳转到相应的页面。
s t a t e P a r a m s 状 态 参 数 在 上 面 提 及 使 用 stateParams状态参数在上面提及使用 stateParams状态参数在上面提及使用stateparams来提取在url中的不同参数。该服务的作用是处理url的不同部分。例如,当上述的inbox状态是这样时:url:’/inbox/:inboxId/messages/{sorted}?from&to’//当用户访问者链接时:’/inbox/123/messages/ascending?from=10&to=20’
$stateParams对象的值为:{inboxId:‘123’,sorted:‘ascending’,from:10,to:20}
详细讲解
3.常见问题
watch的深度监听是什么意思呢?有什么优缺点呢?
4.解决方案
w a t c h 在 对 待 原 始 类 型 和 引 用 类 型 会 有 不 同 的 处 理 方 式 , 这 就 要 首 先 说 一 说 watch在对待原始类型和引用类型会有不同的处理方式,这就要首先说一说 watch在对待原始类型和引用类型会有不同的处理方式,这就要首先说一说watch函数的第三个参数。在前面的例子中,我们知道, w a t c h 函 数 有 接 收 两 个 参 数 , 第 一 个 参 数 是 需 要 监 视 的 对 象 , 第 二 个 参 数 是 在 监 视 对 象 发 生 变 化 时 需 要 调 用 的 函 数 , 实 际 上 watch函数有接收两个参数,第一个参数是需要监视的对象,第二个参数是在监视对象发生变化时需要调用的函数,实际上 watch函数有接收两个参数,第一个参数是需要监视的对象,第二个参数是在监视对象发生变化时需要调用的函数,实际上watch还有第三个参数,它在默认情况下是false。在默认情况下,即不显式指明第三个参数或者将其指明为false时,我们进行的监视叫做“引用监视”。引用监视的原词的“referencewatch”,它的意思是只要监视的对象引用没有发生变化,就不算它发生了变化。具体来说,在上面的例子中,只要是items的引用没有发生变化,就算items中的一些属性发生了变化,$watch也会当做没有看见。
如果我们将 w a t c h 的 第 三 个 变 量 设 置 为 t r u e , 那 么 此 时 我 们 进 行 的 监 视 叫 做 “ 全 等 监 视 ” , 原 词 是 “ e q u a l i t y w a t c h ” 。 此 时 , 只 要 watch的第三个变量设置为true,那么此时我们进行的监视叫做“全等监视”,原词是“equalitywatch”。此时,只要 watch的第三个变量设置为true,那么此时我们进行的监视叫做“全等监视”,原词是“equalitywatch”。此时,只要watch的对象有一点风吹草动,它马上就跳出来
既然全等监视这么好,那么我们为什么不直接用全等监视呢?当然,任何事情都有好的坏的两个方面,全等监视固然是好,但是它在运行时需要先遍历整个监视对象,然后在每次$digest之前使用angular.copy()将整个对象深拷贝一遍然后在运行之后用angular.equal()将前后的对象进行对比,上面的例子中因为items比较简单,因此可能性能上不会有什么差别,但是到了实际生产时,我们要面对的数据千千万万,可能因为全等监视这一个设置就会消耗大量的资源,让应用停滞不前
5.编码实战
6.扩展思考
7.参考文献
参考一:深度理解scope
参考二:原始数据类型和对象类型的区别及深度拷贝解析
8.更多讨论
1 作用域的继承方式是什么?
答: angular里面的作用域是通过原型链的方式来实现继承的。
2 $watch脏检测原理
答: scope通过
w
a
t
c
h
方
法
向
t
h
i
s
.
w
a
t
c
h
e
r
s
数
组
中
添
加
w
a
t
c
h
e
r
对
象
(
包
含
w
a
t
c
h
F
n
,
l
i
s
t
e
n
e
r
F
n
,
v
a
l
u
e
E
q
,
l
a
s
t
四
个
属
性
)
。
每
当
watch方法向this. watchers数组中添加watcher对象(包含watchFn,listenerFn,valueEq,last四个属性)。每当
watch方法向this.watchers数组中添加watcher对象(包含watchFn,listenerFn,valueEq,last四个属性)。每当digest循环被触发时,它会遍历
watchers数组中添加watcher对象(包含watchFn,listenerFn,valueEq,last四个属性)。每当$digest循环被触发时,它会遍历
watchers数组,执行watcher中的watchFn,获取当前scope上某属性的值(一个watcher对应scope上一个被监听属性),然后去同watcher中的last(上一次的值)做比较,若两值不相等,就执行listenerFn。
3 怎么定义或修改$rootScope作用域的属性和方法
答: 可以将 r o o t S c o p e 注 入 到 任 何 一 个 控 制 器 的 f u n c t i o n ( ) 里 面 , 然 后 在 该 方 法 里 面 就 可 以 定 义 rootScope 注入到任何一个控制器的function()里面,然后在该方法里面就可以定义 rootScope注入到任何一个控制器的function()里面,然后在该方法里面就可以定义rootScope的属性和方法。