深入理解AngularJs-scope(一)中,我们对AngularJs的脏检测及其触发、异步任务队列进行了学习。紧接上一篇文章 深入理解AngularJs-scope(一),我们来看看scope对以下两个特性的实现。

  1. scope的继承机制和 isolated scope;
  2. 依赖于scope的事件系统: $on, $broadcast, $emit;

scope的继承机制

  在上一篇文章中,我们创建了scope类,并在scope.prototype上实现了脏检测和异步任务相关的各个方法。

  现在,我们来看看AngularJs中,scope之间是如何通过继承联系在一起的,如何从parentScope上获取properties。实际上,得益于javascript的原型继承机制,要实现scope的继承相当的简单,代码如下:

 Scope.prototype.$new = function(isolated, parent) {
var child;
parent = parent || this; if(isolated) {
child = new Scope();
child.$root = parent.$root;
child.$$asyncQueue = parent.$$asyncQueue;
child.$$postDigestQueue = parent.$$postDigestQueue;
child.$$applyAsyncQueue = parent.$$applyAsyncQueue;
} else {
var ChildScope = function() {};
ChildScope.prototype = this;
child = new ChildScope();
} parent.$$children.push(child); child.$$watchers = []; // shadow这个prop,使成为每个scope独立拥有这个prop
child.$$listeners = {}; // shadow这个prop, 存储包含自定义事件键值对的对象
child.$$children = []; // shadow这个prop,使成为每个scope独立拥有这个prop
child.$parent = parent; // 缓存parentScope, 以便让scope上的其他method能够使用它,比如$destroy return child;
};

  在我们使用AngularJs进行开发时,$new方法的调用无处不在。大部分情况下并不需要我们手动调用,只是指令自己做了创建scope的工作。

  $new方法有两个参数:

    isolated-布尔值,表示新建的scope是不是 isolated scope(孤立的scope)。

    parent-支持传入一个其他scope来作为 AngularJs scope机制中的parentScope。    

  AngularJs中的scope分为两种,一种是普通scope,如上面代码13行所示,普通scope的prototype指向parentScope, 故能够通过原型链获取到parentScope上的properties。

                  另一种是isolated(孤立) scope, isolated是通过 Scope构造函数创建,它的protorype是指向scope构造函数的,并不是parentScope,所以不能从原型链访问parentScope的properties。

  代码19行至22对新scope的$$watchers、$$listeners、$$children、$parent进行了初始化,因为这些属性是每个scope实例自己拥有、自己维护的。

scope的事件系统:订阅/发布

  AngularJs 也为开发者提供了一套事件系统供开发者进行事件的绑定和触发,基于 publish/subscribe 设计模式。其中包含3个核心方法:$on, $emit, $broadcast。

  $on: 在scope上绑定自定义事件,即向scope的$$listeners数组中插入listener回调函数。返回事件销毁函数。

 Scope.prototype.$on = function(eventName, listener) {
var listeners = this.$$listeners[eventName]; if(!listeners) {
this.$$listeners[eventName] = listeners = [];
} listeners.push(listener); return function(eventName) {
var index = listeners.indexOf(listener); if(index >= 0) {
listeners[index] = null;
}
};
};

  $emit: 沿着scope -> parentScope 向上发射事件,执行对应的回调函数。

Scope.prototype.$emit = function(eventName) {
var propagationStopped = false;
var event = {
name: eventName,
targetScope: this,
stopPropagation: function() {
propagationStopped = true;
},
preventDefault: function() {
event.defaultPrevented = true;
}
}; // 把event和additionalArgs拼接成新数组,通过apply方法传入listener, 使参数获取方式正常
var listenerArgs = [event].concat(_.tail(arguments));
var scope = this; do {
event.currentScope = scope;
scope.$$fireEventOnScope(eventName, listenerArgs);
scope = scope.$parent; // 通过改变scope引用 实现向上传播的关键代码
} while (scope && !propagationStopped); event.currentScope = null; return event;
};

   $broadcast: 向下广播事件,并触发对应的回调函数。$broadcast有一点特殊,一旦开始向下广播,就不能中断。

         Scope.prototype.$broadcast = function(eventName) {
var event = {
name: eventName,
targetScope: this,
preventDefault: function() {
event.defaultPrevented = true;
}
}; // 把event和additionalArgs拼接成新数组,通过apply方法传入listener, 使参数获取方式正常
var listenerArgs = [event].concat(_.tail(arguments)); this.$$everyScope(function(scope) {
event.currentScope = scope;
scope.$$fireEventOnScope(eventName, listenerArgs);
return true;
}); event.currentScope = null; return event;
};

这两篇用到的工具函数我都放在后面,由于事件系统的代码比较简单,就不再做过多说明。

工具方法1: $$fileEventOnScope

 /*  $emit 和 $broadcast中 提取出的 fire event listener函数
angularjs源码没有这个方法,其中只是重复了这些代码, 本书作者提出了重复代码
*/
Scope.prototype.$$fireEventOnScope = function(eventName, listenerArgs) { var listeners = this.$$listeners[eventName] || [];
var i = 0; while(i < listeners.length) {
if(listeners[i] === null) {
listeners.splice(i, 1);
} else {
try {
listeners[i].apply(null, listenerArgs);
} catch(e) {
console.error(e);
}
i++;
}
} return event;
};

工具方法2: $$everyScope

 /* 为使$digest循环能够递归child scope上的watchers的工具方法
这个方法还用于实现$broadcast
*/
Scope.prototype.$$everyScope = function(fn) {
if(fn(this)) {
return this.$$children.every(function(child) {
return child.$$everyScope(fn);
});
} else {
return false;
}
};

总结:

  这两篇文章提供了与scope相关的脏检测,$watch, 异步任务,继承机制,事件系统的代码及一点补充分析。弄明白了这些机制是如何实现的,当你在开发工作中用到这些东西时,一定会多一份自信,多一份游刃有余。希望这两篇文章能够帮助到正在使用angular1.x开发的朋友。如有错误,请不吝指出~!谢谢~

深入理解AngularJs-scope(二)的更多相关文章

  1. 深入理解AngularJs-scope(一)

    进入正文前的说明:本文中的示例代码并非AngularJs源码,而是来自书籍<<Build Your Own AngularJs>>, 这本书的作者仅依赖jquery和lodas ...

  2. 理解AngularJS生命周期:利用ng-repeat动态解析自定义directive

    ng-repeat是AngularJS中一个非常重要和有意思的directive,常见的用法之一是将某种自定义directive和ng-repeat一起使用,循环地来渲染开发者所需要的组件.比如现在有 ...

  3. 转: 理解AngularJS中的依赖注入

    理解AngularJS中的依赖注入 AngularJS中的依赖注入非常的有用,它同时也是我们能够轻松对组件进行测试的关键所在.在本文中我们将会解释AngularJS依赖注入系统是如何运行的. Prov ...

  4. 理解AngularJS中的依赖注入

    点击查看AngularJS系列目录 理解AngularJS中的依赖注入 AngularJS中的依赖注入非常的有用,它同时也是我们能够轻松对组件进行测试的关键所在.在本文中我们将会解释AngularJS ...

  5. AngularJS Scope(作用域)

    1. AngularJS Scope(作用域) Scope(作用域) 是应用在 HTML (视图) 和 JavaScript (控制器)之间的纽带. Scope 是一个对象,有可用的方法和属性. Sc ...

  6. 理解ThreadLocal(之二)

    想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使用方法和实现原理.首先,本文先谈一下对ThreadLocal的理解,然后根据ThreadLocal类的源码 ...

  7. AngularJS进阶(二十七)实现二维码信息的集成思路

    AngularJS实现二维码信息的集成思路        赠人玫瑰,手留余香.若您感觉此篇博文对您有用,请花费2秒时间点个赞,您的鼓励是我不断前进的动力,与君共勉!      注:点击此处进行知识充电 ...

  8. AngularJS学习之旅—AngularJS Scope作用域(五)

    1.AngularJS Scope(作用域) Scope(作用域) 是应用在 HTML (视图) 和 JavaScript (控制器)之间的纽带. Scope 是一个对象,有可用的方法和属性. Sco ...

  9. 深入理解C/C++二维数组

    深入理解C/C++二维数组 前言 本来以为自己对二维数组的理解还可以,没感觉有什么,但是今天小伙伴问了一个问题感觉迷惑了好久,于是决定细致的记录一下,一步一步的探究各种关于二维数组的问题,巩固基础. ...

随机推荐

  1. ASP.NET MVC案例教程(基于ASP.NET MVC beta)——第四篇:传递表单数据

    摘要      本文将完成我们“MVC公告发布系统”的公告发布功能,以此展示在ASP.NET MVC中如何传递处理表单的数据. 前言      通过前几篇文章,我们已经能比较自如的使用ASP.NET ...

  2. ES6 数组、对象的扩展

    8. 数组的扩展 扩展运算符(...),将一个数组转为用逗号分隔的参数序列. 复制数组 const a2=[...a1] 合并数组 [...arr1, ...arr2, ...arr3]; arr1. ...

  3. c#中反射的用法(即如何根据字符找到已定义的变量)

    2013-07-20 08:06 720人阅读 评论(0) 收藏 举报  分类: C#(9)  作者同类文章 X 版权声明:本文为博主原创文章,未经博主允许不得转载. 常常羡慕javascript中, ...

  4. 【Codeforces Round #431 (Div. 2) A】Odds and Ends

    [链接]点击打开链接 [题意] 让你把一个数组分成奇数个部分. 且每个部分的长度都是奇数. [题解] 很简单的脑洞题. 开头和结尾一定要为奇数,然后 n为奇数的话,就选整个数组咯. n为偶数的话,不能 ...

  5. ASP.NET MVC 入门4、Controller与Action

    原帖地址:http://www.cnblogs.com/QLeelulu/archive/2008/10/04/1303672.html Controller是MVC中比較重要的一部分.差点儿全部的业 ...

  6. echarts+百度地图+vue 填坑记(一)(百度地图、鼠标移入移出标注,信息框会产生闪烁)

    大概七月底开始实习,到现在经历了两个完整的项目(c2b). 因为开发时间紧,任务重,所以在开发过程踩到的坑都没时间去记录. 现在在开发一个某链运输监控系统,到了收尾阶段,有时间写博客了!开心! 一.鼠 ...

  7. 快速创建SSH信任实现无密码登录

    1. 生成本机的公私钥匙对[oracle@Oracle11_2 scripts]$ -t rsa Generating public/private rsa key pair. Enter file ...

  8. SQLcl

    参考博客: https://wangfanggang.com/Oracle/sqlcl/ 执行show sqlformat可以看到当前格式化样式为:default 让我们修改下显示结果的样式:set ...

  9. u-boot分析1:Nandflash、Norflash启动

    了解u-boot之前首先了解下Bootloader,简单说Bootloader就是一段小程序,它在系统上电时开始运行,初始化硬件设备,准备好软件环境,最后调用操作系统内核. u-boot全称:Univ ...

  10. 【习题 5-9 UVA - 1596】Bug Hunt

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] map模拟 map<string,int>记录每个数组的大小 map <pair<string, int&g ...