学习Angular中作用域需要注意的坑


Posted in Javascript onAugust 17, 2016

Angular作用域

在用angular搭建的网页应用中,作用域(scope)这个概念是贯穿其中的。在angular的视图(view)中的很多指令是会创建一个作用域的,例如 ng-app , ng-controller 等。这个作用域就是我们在写控制器构造函数时注入的 $scope (angular1.2之前的版本),他是视图模型(view model)中的一个概念。我们的数据模型(model)就是定义在作用域中的。

Angular作用域的坑

用过angular的人应该都会经过一个过程,就是刚开始还是小白的时候,刚看见数据双向绑定觉得很牛逼,

Angular中作用域的坑1

管他三七二十一直接开始用,一顿绑定。绑定完之后,如果你运气好(懂得angular作用域原理的老鸟无视),那么双向绑定就开始如愿工作了,这时候我们也觉得自己好厉害,居然可以这么快就实现“双向绑定”这个才听说不久的新功能了。

那么为什么上面说双向绑定是因为运气好才能正常工作呢?因为新手刚开始学angular的时候,无非就是看教程然后改动其中的代码实现自己的业务需求,能刚开始就去学习官方文档的选手就算有也是少数,所以这样,大多数刚学习angular的朋友实际上不太了解其中的原理,但是觉得自己已经会用了。

好说了这么多,那我们来看看如果一个新手刚开始给作用域中指定数据模型并且进行双向绑定时,运气不那么好的情况。这种情况下,就会遇到上面说的坑,先来看看代码

// html
<div ng-controller="OuterCtrl">
  <span ng-bind="a"></span>
  <div ng-controller="InnerCtrl">
    <span ng-bind="a"></span>
    <button ng-click="a=a+1">递增</button>
  </div>
</div>

// javascript
function OuterCtrl($scope) {
  $scope.a = 1;
}
function InnerCtrl() {}

上面的代码就是一个极其简单的双向绑定的例子。页面加载以后,外部 div 和内部 div 中都会显示1。当按了递增按钮之后,会发现只有内部的1变成了2,继续按也是一样,只有内部的数字会递增。那么这时候,新手往往就慌了,说好的神奇的双向绑定呢?

Angular中作用域的坑2

这个时候宝宝就有点小情绪了,stackoverflow走起,官方文档走起,最后发现确实有解决方法,比如说将 a 写成一个对象的属性 data.a

// html
<div ng-controller="OuterCtrl">
  <span ng-bind="data.a"></span>
  <div ng-controller="InnerCtrl">
    <span ng-bind="data.a"></span>
    <button ng-click="data.a=data.a+1">递增</button>
  </div>
</div>

// javascript
function OuterCtrl($scope) {
  $scope.data = {
    a: 1
  };
}
function InnerCtrl() {}

然后发现,居然可以工作了,两个数字都跟着递增了,我是双向绑定之王……然后就扔一边也不管具体的原理继续学习下一部分教程了。这其实就是我当初学习angular的心路历程,实在惭愧做了应用部署到生产环境之后才想起来去研究研究内部的原理。

坑总是要填的

废话说了那么多,坑也去踩了,下面进入填坑阶段,也就是这个坑是为什么会出现为什么写成对象的属性就能解决。其实知道了原理之后,是很容易理解的。angular的内外层作用域之间是基于javascript的原型链来实现的继承,并且只使用了原型链继承方法,有点JavaScript基础的朋友应该就能瞬间反应过来,子类原型对象中的引用类型值和父类实例对象中的引用类型值是引用的同一个,而基本类型值则会覆盖父类对象中的基本类型值,这其实也是组合继承存在的原因,因为光用原型链继承会带来上诉问题,扯得有点远

总之这里,我们可以这样来看待第一个例子:

function OuterCtrl() {
  this.a = 1;
}
function InnerCtrl() {}

var outer = new OuterCtrl();
InnerCtrl.prototype = outer;
var inner = new InnerCtrl();
inner.a = inner.a + 1;

这里,我们将内部的控制器的构造函数的原型对象设置为外部作用域对象,这样产生的内部作用域对象就继承了外部对象 outer 中的属性 a 。这个属性是个基本类型值,对内部对象的属性 a 进行访问的时候,由于内部对象本身不存在这样的属性,就会从它的原型对象中查找,原型对象 outer 中存在这样的属性,于是返回值,没有问题,但是如果我们对内部作用域对象的 a 属性赋值的话,问题就出来了。 inner.a = inner.a + 1; 这个语句实际上进行了前面说的查找 a 属性值的过程,然后将返回的值赋值给了内部作用域对象的 a 属性,由于 a 属性是不存在的,因此创建了一个 a 的基本类型值属性,屏蔽了外层作用域对象 outer 中的 a 属性,这个坑就这么出来了。

因此,如果我们将基本类型值属性换成引用类型值属性的话,问题就能够得到解决,因为他们两个对象对应的属性是引用的同一个引用类型值,不管在哪对它进行修改都会反应在所有引用他的对象上。

总结

以上就是关于Angular中作用域需要注意的坑的全部内容,希望本文的内容对大家学习Angular中的作用域能有所帮助。

Javascript 相关文章推荐
DIV+CSS+JS不间断横向滚动实现代码
Mar 19 Javascript
JS实现两个大数(整数)相乘
Apr 28 Javascript
javascript实现详细时间提醒信息效果的方法
Mar 11 Javascript
JS实现状态栏跑马灯文字效果代码
Oct 24 Javascript
归纳下js面向对象的几种常见写法总结
Aug 24 Javascript
轻松掌握JavaScript中介者模式
Aug 26 Javascript
Vue.js实现拖放效果的实例
Sep 30 Javascript
JS实现自动阅读单词(有道单词本添加功能)
Nov 14 Javascript
Vue中的数据监听和数据交互案例解析
Jul 12 Javascript
Angular5.0 子组件通过service传递值给父组件的方法
Jul 13 Javascript
vue实现百度下拉列表交互操作示例
Mar 12 Javascript
JS字符串和数组如何实现相互转化
Jul 02 Javascript
js enter键激发事件实例代码
Aug 17 #Javascript
jquery过滤特殊字符',防sql注入的实现方法
Aug 17 #Javascript
js替换字符串中所有指定的字符(实现代码)
Aug 17 #Javascript
在javascript中使用com组件的简单实现方法
Aug 17 #Javascript
模拟javascript中的sort排序(简单实例)
Aug 17 #Javascript
js replace(a,b)之替换字符串中所有指定字符的方法
Aug 17 #Javascript
BOM系列第一篇之定时器setTimeout和setInterval
Aug 17 #Javascript
You might like
精致的人儿就要挑杯子喝咖啡
2021/03/03 冲泡冲煮
微博短链接算法php版本实现代码
2012/09/15 PHP
PHP session_start()问题解疑(详细介绍)
2013/07/05 PHP
php在线解压ZIP文件的方法
2014/12/30 PHP
php中array_multisort对多维数组排序的方法
2020/06/21 PHP
javascript onkeydown,onkeyup,onkeypress,onclick,ondblclick
2009/02/04 Javascript
如何利用AngularJS打造一款简单Web应用
2015/12/05 Javascript
JS获取中文拼音首字母并通过拼音首字母快速查找页面内对应中文内容的方法【附demo源码】
2016/08/19 Javascript
jQuery、zepto、js常用小技巧
2017/02/12 Javascript
Vue2.x中的父组件传递数据至子组件的方法
2017/05/01 Javascript
webstorm添加vue.js支持的方法教程
2017/07/05 Javascript
AngularJS实现表单验证功能详解
2017/10/12 Javascript
webpack配置之后端渲染详解
2017/10/26 Javascript
JS计算两个数组的交集、差集、并集、补集(多种实现方式)
2019/05/21 Javascript
深入了解JavaScript 的 WebAssembly
2019/06/15 Javascript
百度小程序之间的页面通信过程详解
2019/07/18 Javascript
layer 刷新某个页面的实现方法
2019/09/05 Javascript
详解nginx配置vue h5 history去除#号
2020/11/09 Javascript
vue自定义插件封装,实现简易的elementUi的Message和MessageBox的示例
2020/11/20 Vue.js
[15:35]教你分分钟做大人:天怒法师
2014/10/30 DOTA
matplotlib在python上绘制3D散点图实例详解
2017/12/09 Python
python打包压缩、读取指定目录下的指定类型文件
2018/04/12 Python
python pandas实现excel转为html格式的方法
2018/10/23 Python
python进行TCP端口扫描的实现
2018/12/21 Python
Django数据库类库MySQLdb使用详解
2019/04/28 Python
python 实现检验33品种数据是否是正态分布
2019/12/09 Python
python 中值滤波,椒盐去噪,图片增强实例
2019/12/18 Python
Django后端按照日期查询的方法教程
2021/02/28 Python
使用HTML5和CSS3制作一个模态框的示例
2018/03/07 HTML / CSS
KIKO MILANO英国官网:意大利知名化妆品和护肤品品牌
2017/09/25 全球购物
New delete 与malloc free 的联系与区别
2013/02/04 面试题
客服专员岗位职责范本
2013/11/29 职场文书
单位一把手群众路线四风问题整改措施
2014/09/25 职场文书
出差报告怎么写
2014/11/06 职场文书
委托书格式要求
2015/01/28 职场文书
Python集合的基础操作
2021/11/01 Python