理解《JavaScript设计模式与开发应用》发布-订阅模式的最终版代码
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了理解《JavaScript设计模式与开发应用》发布-订阅模式的最终版代码,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6320字,纯文字阅读大概需要10分钟。
内容图文
最近拜读了曾探所著的《JavaScript设计模式与开发应用》一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线空间功能和命名空间功能,以达到先发布再订阅的功能和防止名称冲突的效果。但是令人感到遗憾的是最终代码并没有给出足够的注释。这让像我一样的小白就感到非常的困惑,于是我将这份最终代码仔细研究了一下,并给出了自己的一些理解,鉴于能力有限,文中观点可能并不完全正确,望看到的大大们不吝赐教,谢谢!
下面是添加了个人注释的最终版代码:
1 <! DOCTYPE html > 2 < html > 3 < head > 4 < title ></ title > 5 < meta charset = "utf-8" /> 6 </ head > 7 < body > 8 < script type ="text/javascript" > 9 var Event = ( function (){ // 定义立即调用的对象 10 var global = this , 11 Event, 12 _default = ‘ default ‘ ; 13 Event = function (){ 14 var _listen, // 私有变量 15 _trigger, 16 _remove, 17 _slice = Array.prototype.slice, 18 _shift = Array.prototype.shift, 19 _unshift = Array.prototype.unshift, 20 namespaceCache = {}, 21 _create, 22 find, 23 each = function ( ary, fn ){ 24 var ret; 25 for ( var i = 0 , l = ary.length; i < l; i ++ ){ 26 var n = ary[i]; 27 ret = fn.call( n, i, n); 28 // n(args) 29 } 30 return ret; 31 }; 32 _listen = function ( key, fn, cache ){ 33 if ( ! cache[ key ] ){ 34 cache[ key ] = []; 35 } 36 cache[key].push( fn ); 37 }; 38 _remove = function ( key, cache ,fn){ 39 40 if ( cache[ key ] ){ 41 var fns = cache[key]; 42 if ( fn ){ 43 for ( var i = fns.length - 1 ; i >= 0 ; i -- ){ 44 // 原文for( var i = cache[ key ].length; i >= 0; i-- ){ 45 // if( cache[ key ] === fn )我认为不妥。 46 if ( fns[i] === fn ){ 47 fns.splice( i, 1 ); 48 } 49 } 50 } else { 51 cache[ key ] = []; 52 } 53 } 54 }; 55 _trigger = function (){ 56 var cache = _shift.call(arguments), 57 key = _shift.call(arguments), 58 args = arguments, 59 _self = this , 60 ret, 61 stack = cache[ key ]; 62 if ( ! stack || ! stack.length ){ 63 return ; 64 } 65 return each( stack, function (){ 66 return this .apply( _self, args ); // _self = object{} //n(args) 67 }); 68 }; 69 _create = function ( namespace ){ 70 var namespace = namespace || _default; 71 var cache = {}, 72 offlineStack = [], 73 // 离线事件 74 ret = { 75 listen: function ( key, fn, last ){ 76 _listen( key, fn, cache ); 77 if ( offlineStack === null ){ 78 return ; 79 } 80 if ( last === ‘ last ‘ ){ 81 offlineStack.length && offlineStack.pop()(); 82 } else { 83 each( offlineStack, function (){ 84 this (); 85 }); 86 } 87 offlineStack = null ; 88 }, 89 one: function ( key, fn, last ){ 90 _remove( key, cache ); 91 // 移除已存在的listen事件 92 this .listen( key, fn ,last ); 93 }, 94 remove: function ( key, fn ){ 95 _remove( key, cache ,fn); 96 }, 97 trigger: function (){ 98 var fn, 99 args, 100 _self = this ; 101 _unshift.call( arguments, cache ); 102 args = arguments; 103 fn = function (){ 104 return _trigger.apply( _self, args ); 105 // _self的作用是将—trigger方法绑定到ret里面来,从而能使用args 106 107 }; 108 if ( offlineStack ){ 109 return offlineStack.push( fn ); 110 } 111 return fn(); 112 } 113 }; 114 return namespace ? 115 ( namespaceCache[ namespace ] ? namespaceCache[ namespace ] : 116 namespaceCache[ namespace ] = ret ) 117 : ret; 118 }; 119 return { 120 // 所有方法均先创建一个离线空间 调用create方法,并传递空参数, 返回ret = object{}; 121 create: _create, 122 one: function ( key,fn, last ){ 123 var event = this .create( ); 124 event.one( key,fn,last ); 125 }, 126 remove: function ( key,fn ){ 127 var event = this .create( ); 128 event.remove( key,fn ); 129 }, 130 listen: function ( key, fn, last ){ 131 var event = this .create( ); 132 event.listen( key, fn, last ); 133 }, 134 trigger: function (){ 135 var event = this .create( ); 136 // event = ret ; 137 event.trigger.apply( this , arguments ); 138 // 将arguments传递给ret.trigger 139 } 140 }; 141 }(); 142 return Event; 143 })(); 144 Event.trigger( ‘ click ‘ , 5 ); 145 // 将其存入offlineStack等待调用 146 Event.listen( ‘ click ‘ , function ( a ){ 147 console.log( a ); 148 }); 149 Event.create( ‘ namespace1 ‘ ).listen( ‘ click ‘ , function ( a ){ 150 console.log( a ); 151 }); 152 // namespace的作用是,没有时,我们返回简单的ret对象。有时,我们返回namespase下的一个键值为namespase1的对象 153 154 Event.create( ‘ namespace1 ‘ ).trigger( ‘ click ‘ , 1 ); 155 // 将调用namespase1的trigger方法 156 Event.one( ‘ click ‘ , function (a){ 157 console.log( " this is the one‘s " + a); 158 } , " last " );
159 Event.trigger( ‘ click ‘ , 666 ); 160 Event.listen( ‘ click ‘ , function ( a ){ 161 console.log( " this is a simple " + a ); 162 }); 163 Event.listen( ‘ click ‘ , function ( a ){ 164 console.log( " this is also a simple " + a ); 165 });
166 Event.trigger( ‘ click ‘ , " hahaha " ); 167 Event.one( ‘ click ‘ , function (a){ 168 console.log( " this is the one‘s " + a + " and it‘s the only " + a); 169 } , " last " ); 170 Event.trigger( ‘ click ‘ , " hahahahahahahaha " ); 171 </ script > 172 </ body > 173 </ html >
我认为对于代码的理解可以分为两个阶段,第一个阶段:理解代码的含义,明白代码是怎么运行的;第二个阶段:深刻理解代码本质,并能够独立写出代码。当然作为小白的我还没有能力达到第二阶段,也只能讲讲自己第一阶段的理解了。
有同学曾和我讨论过这段代码里面one()的作用,通过最后面添加的实例不难理解,它的作用是清除之前存在的(某个命名空间的)订阅事件,再添加唯一的一个订阅事件。然后对于一些细节的理解我通过注释添加在了代码中,如有感兴趣的同学,欢迎前来和我讨论,或者有觉得我的观点有失偏颇的,希望能不吝赐教。
最后我认为抛开个模块之间有点复杂的通信外,这段代码最让人难以理解的就是this的应用了,JavaScript里面的this被认为是一个巨大的坑,但运用得当,必会事半功倍。这里我先简要谈谈对this的理解:
JavaScript里面的this大致可以分为4种情况:第一种情况,方法调用模式:函数被保存为对象的一个方法,当这个方法被调用时,this指向该对象;第二种情况,函数调用模式:此模式下,this被绑定到全局对象,这被认为是一个设计错误;第三种情况,构造器调用模式:如果一个函数前面带上new来调用,那么将创建一个隐藏链接到该函数的prototype成员的新对象,同时this绑定到新对象上;第四种情况,call,apply调用模式:该模式类似于继承,将执行call,apply操作的对象绑定到第一个参数上,同时将this绑定到第一个参数上,例如:
<! DOCTYPE html > < html > < head > < title ></ title > < meta charset ="utf-8" > </ head > < body > < script type ="text/javascript" > var name = " I am window " ; var obj = { name: " sharpxiajun " , job: " Software " , ftn01: function (obj){ obj.show(); }, ftn02: function (ftn){ ftn(); }, ftn03: function (ftn){ ftn.call( this ); } }; function Person(name){ this .name = name; this .show = function (){ console.log( " 姓名: " + this .name); console.log( this ); } } var p = new Person( " Person " ); obj.ftn01(p); obj.ftn02( function (){ console.log( this .name); console.log( this ); }); obj.ftn03( function (){ console.log( this .name); console.log( this ); }); </ script > </ body > </ html >
实例来源: 夏天的森林 《JavaScript技术难点(三)之this、new、apply和call详解》
输出结果为:
但是发布-订阅模式的的this应用依然让我感到费解:
这两处this的使用不像平常见到的那种隐式调用或者用做参数,而是直接当做函数使用(表述不定对),这让我有点难以理解,但是他们达到的效果就是类似的,起到的是传递参数的作用。那么这里的this我否可以理解为也是通过call,apply将其绑定到第一个参数上面呢?希望看到的大大能帮我解释一下,谢谢!
原文:http://www.cnblogs.com/Jewl/p/5443154.html
内容总结
以上是互联网集市为您收集整理的理解《JavaScript设计模式与开发应用》发布-订阅模式的最终版代码全部内容,希望文章能够帮你解决理解《JavaScript设计模式与开发应用》发布-订阅模式的最终版代码所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。