学习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 相关文章推荐
CSDN轮换广告图片轮换效果
Mar 27 Javascript
判断浏览器的javascript版本的代码
Sep 03 Javascript
Dom 是什么的详细说明
Oct 25 Javascript
JS获取页面input控件中所有text控件并追加样式属性
Feb 25 Javascript
JavaScript版TAB选项卡效果实例
Aug 16 Javascript
js闭包所用的场合以及优缺点分析
Jun 22 Javascript
JS+Canvas绘制时钟效果
Aug 20 Javascript
轮播的简单实现方法
Jul 28 Javascript
微信小程序 删除项目工程实现步骤
Nov 10 Javascript
Angular5.1新功能分享
Dec 21 Javascript
关于vue v-for循环解决img标签的src动态绑定问题
Sep 18 Javascript
Node.js事件的正确使用方法
Apr 05 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
php 提速工具eAccelerator 配置参数详解
2010/05/16 PHP
Yii2中设置与获取别名的函数(setAlias和getAlias)用法分析
2016/07/25 PHP
PHP实现图片的等比缩放和Logo水印功能示例
2017/05/04 PHP
jquery获得页面元素的坐标值实现思路及代码
2013/04/15 Javascript
new Date()问题在ie8下面的处理方法
2014/07/31 Javascript
jQuery中has()方法用法实例
2015/01/06 Javascript
使用DNode实现php和nodejs之间通信的简单实例
2015/07/06 NodeJs
Vue.js 表单校验插件
2016/08/14 Javascript
jQuery Easyui Tabs扩展根据自定义属性打开页签
2016/08/15 Javascript
深入掌握 react的 setState的工作机制
2017/09/27 Javascript
Vue的实例、生命周期与Vue脚手架(vue-cli)实例详解
2017/12/27 Javascript
jQuery中event.target和this的区别详解
2020/08/13 jQuery
[02:15]你好,这就是DOTA!
2015/08/05 DOTA
[51:17]完美世界DOTA2联赛循环赛Inki vs DeMonsTer 第二场 10月30日
2020/10/31 DOTA
Python发送Email方法实例
2014/08/21 Python
Linux上安装Python的PIL和Pillow库处理图片的实例教程
2016/06/23 Python
详解MySQL数据类型int(M)中M的含义
2016/11/20 Python
python PyTorch预训练示例
2018/02/11 Python
python 用lambda函数替换for循环的方法
2018/06/09 Python
python操作excel的包(openpyxl、xlsxwriter)
2018/06/11 Python
Python列表生成式与生成器操作示例
2018/08/01 Python
python中bytes和str类型的区别
2019/10/21 Python
关于tf.reverse_sequence()简述
2020/01/20 Python
Python3中configparser模块读写ini文件并解析配置的用法详解
2020/02/18 Python
如何在sublime编辑器中安装python
2020/05/20 Python
Python 实现劳拉游戏的实例代码(四连环、重力四子棋)
2021/03/03 Python
英国马莎百货官网:Marks & Spencer
2016/07/29 全球购物
计算机个人求职信范例
2014/01/24 职场文书
区三好学生主要事迹
2014/01/30 职场文书
感恩老师的演讲稿
2014/05/06 职场文书
2014年工作总结与下年工作计划
2014/11/27 职场文书
经理助理岗位职责
2015/02/02 职场文书
聘任书格式及范文
2015/09/21 职场文书
教你如何用python开发一款数字推盘小游戏
2021/04/14 Python
python opencv旋转图片的使用方法
2021/06/04 Python
Android Flutter实现图片滑动切换效果
2022/04/07 Java/Android