For the user to call the function is more convenient and flexible, so we define the parameters need not fixed data type, such as:
Mylibs.on (' event ', FN);
Mylibs.on ({
' Event1 ': fn1,
' Event2 ': fn2,
' Event3 ': fn3
});
Mylibs.on (' event1 event2 event3 ', FN);
This is an example of a custom event, with three types of arguments: 1, event name + callback 2, passing an object containing event name and callback 3, multiple event names + a callback
How do you think this function is good, perhaps most people first think of the unified data type to deal with the specific logic, as follows:
//matches any whitespace character, including \n,\r,\f,\t,\v (newline, carriage return, Space, tab, etc.)varEventsplitter =/\s+/;varMylibs ={on:function(name, callback, context) {if(typeofName = = = ' String ') {Name={name:callback}; } if(eventsplitter.test (name)) {varNames =Name.split (eventsplitter), name= {}; for(vari = 0, length = names.length; i < length; i++) {Name[names[i]]=callback; } } //The data type is unified and the loop is executed (the default data type is an object, so it is not judged above) for(varKeyinchname) { //Specific Logic ... } return This; }};
This kind of writing seems good, the first unified processing data type, solve the problem of different parameters. However, the function looks a little bloated, and if the parameters add several types, then the corresponding will also add the judgment statement in the function body, and put the specific logic code in the For loop is not an elegant approach.
We can try to extract the judgment statement and write it in a separate function.
varMylibs ={on:function(name, callback, context) {name= This. EVENTSAPI (Name,callback); for(varKeyinchname) { //Specific Logic ... } return This; }, Eventsapi:function(name,callback) {if(typeofName = = = ' String '){ return{name:callback}; } if(eventsplitter.test (name)) {varNames =Name.split (eventsplitter), name= {}; for(vari = 0, length = names.length; i < length; i++) {Name[names[i]]=callback; } returnname; } returnname; }};
The EVENTSAPI function is created to unify the data types, and the on function is obviously not bloated, and the 2 functions work. But the exact logic code of the on function is still inside the for loop, and we have to figure out a way to pull it out.
The solution can take advantage of recursion, let's deal with the EVENTSAPI function first.
EVENTSAPI:function(obj,action,name,rest) {if(!name)return true; if(typeofName = = = ' object '){ for(varKeyinchname) {obj[action].apply (Obj,[key,name[key]].concat (rest)); } return false; } if(eventsplitter.test (name)) {varNames =Name.split (Eventsplitter); for(vari = 0, length = names.length; i < length; i++) {obj[action].apply (obj, [Names[i]].concat (rest)); } return false; } return true;}
is not a bright, eventsapi function does not uniformly handle the data type, but directly call the on function, when the on function becomes a fixed data type of the function, in fact, is the first form of the argument: an event name + callback.
Let's take a look at the complete code to deepen our understanding.
//matches any whitespace character, including \n,\r,\f,\t,\v (newline, carriage return, Space, tab, etc.)varEventsplitter =/\s+/;varMylibs ={on:function(name, callback, context) {if(! This. EVENTSAPI ( This, ' on ', name, [callback, context]) | | !callback)return This; //Specific Logic ... return This; }, Eventsapi:function(obj,action,name,rest) {if(!name)return true; if(typeofName = = = ' object '){ for(varKeyinchname) {obj[action].apply (Obj,[key,name[key]].concat (rest)); } return false; } if(eventsplitter.test (name)) {varNames =Name.split (Eventsplitter); for(vari = 0, length = names.length; i < length; i++) {obj[action].apply (obj, [Names[i]].concat (rest)); } return false; } return true; }};//Call:Mylibs.on (' event ', FN); Mylibs.on ({' Event1 ': Fn1,' Event2 ': fn2,' Event3 ': Fn3}); Mylibs.on (' Event1 event2 event3 ', FN);
An invariant data type with recursive normalization of function parameters