类似观察者设计模式的JS,问题总结
2017-10-11 11:06
453 查看
熟悉一个老项目的过程中,许多业务功能是在前端完成的,其中有一个技术点就是如何完成主页面与子页面之间的通信,其中很多js看起来很模糊,后来问同事了解到我们这个项目用到了这么一个js文件 主要功能如下
/* * 一个类似观察者设计模式 使用的WEB前端发布(publish) 订阅(subscribe) 的小组件 不需要第3方库的依赖 * * 支持像jquery一样的链式调用风格 * *使用ps.pub / ps.publish 发布事件通知 * *使用ps.sub /ps.subscribe 订阅通知 */ !function(w){ var ps={}, subs={}, tokencache=1, tokenPre="pubAndSub-"; /** * 广播订阅者 */ ps.publish=ps.pub=function(){ var args=getArgsAsArrays(arguments); if(args.length<=0){ throw new Error('广播事件必须要指定事件类型'); aa52 } var event=args[0]; var calls=subs[event]; if(!calls){//不处理没有用户订阅的事件 return; } var ctx = { event: event, args:args.splice(1)}, len=calls.length; for(var i=0;i<len;i++){ ctx.token=calls[i].token; calls[i].callback.apply(ctx,ctx.args); } return this; } /** * 订阅 */ ps.subscribe=ps.sub=function(event,call){ var a=subs[event]=subs[event]||[], instanceToken=tokenPre+tokencache++; a.push({ token:instanceToken, callback:call }); return instanceToken; } //////////////////////util /** * 获取参数列表 转换为[] */ function getArgsAsArrays(arg){ return Array.prototype.slice.call(arg); } w.ps=ps; }(window);
需要先subscribe,后publish,我们做一个小演示
var person = { name: "ning", sayHi: function() { console.log("person sub......"); } }; var msg = ps.sub(person,person.sayHi); ps.pub(person);
我们看看调用sub的代码
ps.subscribe=ps.sub=function(event,call){ var a=subs[event]=subs[event]||[], instanceToken=tokenPre+tokencache++; a.push({ token:instanceToken, callback:call }); return instanceToken; }
在整个JS中先定义了subs这个对象,当我们调用ps.sub的时候,为subs添加了一个event属性,值为[],一个空数组,并将这个空数组的引用给了a,instanceToken只是调用subs时返回的信息,暂且忽略,接着我们,为这个空数组传入了对象,subs这个对象就变成了:
{ Object: [{callback:ƒ (),token:"pubAndSub-1" }] }
其中这个Object就是person对象,ƒ ()就是sayHi那个函数, 那么在调用pub的时候做了什么呢
ps.publish=ps.pub=function(){ var args=getArgsAsArrays(arguments); if(args.length<=0){ throw new Error('广播事件必须要指定事件类型'); } var event=args[0]; var calls=subs[event]; if(!calls){//不处理没有用户订阅的事件 return; } var ctx = { event: event, args:args.splice(1)}, len=calls.length; for(var i=0;i<len;i++){ ctx.token=calls[i].token; calls[i].callback.apply(ctx,ctx.args); } return this; }
getArgsAsArrays是将arguments对象转成数组,在ps.pub(person)时,args就是一个数组,只包含person对象这一个值。 var event=args[0]; //这一行取出数组第一个元素,即person对象 var calls=subs[event]; //拿到这个对象的所有回调函数组成的数组 var ctx = { event: event, args:args.splice(1)} //其中这个对象中的event就是我们的person对象,args.splice(1)则删除了第一个元素,只留下了需要传的参数,在我们这次调用中,只留下一个空数组,因为不需传参。 在for循环中对所有回调函数,以ctx这个对象为作用域,传入args参数,执行函数。 于是在控制台中看到 person sub...... 但是如果我们将person中的sayHi改为如下代码时
var person = { name: "ning", sayName: function() { console.log(this.name); } }; var msg = ps.sub(person,person.sayName); ps.pub(person); //undefined person.sayName(); //ning
这就牵扯到作用域的问题,关键字为apply(),this
当person.sayName()的时候,this代表的是person这个作用域,所欲this.name即ning
但是当使用观察者模式时,调用sayName的代码变为了如下代码
calls[i].callback.apply(ctx,ctx.args);
apply函数的作用是改变函数的作用域,此时调用sayName()的作用域为ctx,ctx中没有name属性,自然就是undefined,如果想要输出名字,则需要将sayName中的代码改为
console.log(this.event.name);//ning
其中的this.event就是ctx对象中的event属性,本次调用中即为person对象
相关文章推荐
- 设计模式学习总结(15) 观察者模式
- 设计模式学习总结-观察者模式(Observer Pattern)
- 关于js设计模式的一些总结和理解
- JS常用的设计模式(3)-——观察者模式
- 所有的问题, 包括自己想象的问题 <<总结项目用到的设计模式>>
- 【js设计模式笔记---观察者模式】
- 设计模式总结—观察者模式
- 【JS 设计模式 】观察者模式之实时改变页面中的金额数
- "围观"设计模式(31)--行为型设计模式总结(模板、观察者、策略、状态、责任链、命令、访问者、中介者、备忘录、解释器)
- 圣思园java se培训总结(82-)(观察者设计模式)
- 设计模式之观察者模式总结
- 设计模式总结之观察者模式
- JS设计模式之观察者模式
- C++技术问题总结-第12篇 设计模式原则
- 【HeadFirst 设计模式总结】2 观察者模式
- 项目中的流程及类似业务的设计模式总结
- js设计模式(10)---观察者模式
- PHP设计模式之JS实现观察者模式
- js设计模式中发布与订阅实现观察者模式例子
- PHP 设计模式 笔记与总结(11)观察者模式