//测试Chrome版本 40.0.2214.115 m //如有错误欢迎指出 //回调函数分析上 http://ezizoo.iteye.com/blog/2204399 //下面所讲是回调函数下 //重点 //此次添加 回调函数的三种状态 //所写的js可直接放入html中运行 //首先三种状态都在什么时候做判断 //onece 也就是执行回调的时候 fire()的时候判断是否已经fired==true //unique 在添加函数的判断数组中是否有这个函数 //memory 在添加函数加上一句判断,当memory为真时,那么在cb.fire()执行后添加的方法也会被再次fire() //需要有一个记录回调到哪一个函数的下标 //思路已经说了,看代码可直接到Callbacks方法这 //下面的一些方法前面都做了分析 //如有不懂可以看下我以前对这些方法的说明 var toString={}.toString; var class2type={}; var hasOwn={}.hasOwnProperty; var isArray=Array.isArray; var indexOf=[].indexOf; var each=function(obj,callback){ var value, length=obj.length, i=0, isArray=isArrayLike(obj); //两种情况 //类数组 if(isArray){ for(;i<length;i++){ //若是返回false,则直接跳出 value=callback.call(obj,i,obj[i]); if(value===false){ break; } } }else{ for(i in obj){ value=callback.call(obj,i,obj[i]); if(value===false){ break; } } } return obj; }; //第二个判断是否像数组一样的对象 var isArrayLike=function(obj){ var length=obj.length; //判断为空 if(obj==null){ return false; } if(type(obj)==="object" ||typeof(obj)==="function"){ return false; } return type(obj)==="array" ||length===0 || (length>0 &&(length-1) in obj); }; //第三个判断类型 var type=function(obj){ //排除为空的 if(obj==null){ return obj+""; } //做判断,如果是object或者function类型的时候 //不是执行后面 return typeof obj==="object" ||typeof obj==="function" ? class2type[toString.call(obj)] : typeof obj; }; each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(_,name){ class2type["[object "+name+"]"]=name.toLowerCase(); }); var isFunction=function(obj){ return type(obj); }; var isWindow=function(obj){ return obj!==null && obj.window===window; }; var isPlainObject=function(obj){ if(type(obj)!=="object" ||obj.nodeType||isWindow(obj)){ return false; } if(hasOwn.call(obj.constructor.prototype,"isPrototypeOf")){ return true; } }; //一个确定数组中是否存在这个值的函数 var inArray=function(arr,elem,i){ return arr===null ? -1 :indexOf.call(arr,elem,i); }; //第一个添加onece //第二个添加memory //只要在添加函数的时候过滤掉就行 var Callbacks=function(options){ options=type(options)==="string" ? createOptions(options) :{}; var i, fired, firing, list=[], fireIndex=list.length, stack=!options.onece && []; //定义一个函数,将数组全部执行一次 fire=function(){ for(;list && fireIndex<list.length;i++,fireIndex++){ //list[i](); //alert(this); list[fireIndex].call(arguments[0]); } fired=true; }, self={ add:function(){ (function add(args){ //对传进来的参数进行解析 //以后可使用each遍历 for(i=0;i<args.length;i++){ if(!options.unique && typeof(args[i])==="function"||(options.unique && inArray(list,args[i])<0)){ //list[i]=arguments[i]; list.push(args[i]); } } })(arguments); if(options.memory){ fire(this); } return this; }, fire:function(){ //if(options.onece && fired){ // fire(this); //}else{ //} //若是写成上述,当onece为false时,第一次就过不去 //再写个fireWith()方法 self.fireWith(this); return this; }, fireWith:function(){ if(list && (!fired || stack)){ fire(this); } return this; } }; return self; }; //写个函数将几种状态解析出来 //参数形式如下'onece','memory' var createOptions1=function(){ var object={}; each(arguments,function(_,flag){ object[flag]=true; }); return object; }; //换一种写法 //参数形式如下'onece memory' var reg=/\S+/g; var createOptions=function(){ var object={}; each(arguments[0].match(reg),function(_,flag){ object[flag]=true; }); return object; }; console.info(createOptions('onece unique')); //附件中有html测试