1. What is a chained call
This is easy to understand, for example:
$(this).setStyle(‘color‘‘red‘).show();
The difference between a generic function call and a chained call: After the method is called, return this the object that is currently calling the method is returned.
function Dog(){ This. run= function(){Alert"The dog is running ....");return This;//Returns the current object, Dog}; This. eat= function(){Alert"After running, the dog is eatting ....");return This;//Returns the current object, Dog}; This. sleep= function(){Alert"After eatting, the dog is running ....");return This;//Returns the current object, Dog}; }//general method of invocation;/* var dog1 =new Dog (); Dog1.run (); Dog1.eat (); Dog1.sleep (); */ varDOG2 =NewDog (); Dog2.run (). Eat (). Sleep ();
2. Break-Chain Call
A chained call is actually two parts:
1. manipulate the object (that is, the DOM element being manipulated, as in the example above)
2. How to do it (specifically what to do, such as the SetStyle and show on the above example)
How to implement Operation object and Operation method
Create a generic $ function:
function $(){ varelements = []; for(varI=0, len=arguments. length; i<len; i++) {varelement =arguments[i];if(typeofelement===' String ') {element = document.getElementById (element); }if(arguments. length==1){returnElement } elements.push (Element); }returnelements;}
However, if you transform this function into a constructor, save those elements as an array in an instance property, and have all the methods defined in the prototype property of the constructor function return a reference to the instance that invokes the method, then it has the ability to chain-call. (Say so much, is at the end of each method return this; ),
I first need to $ change this function to a factory method, which is responsible for creating objects that support chained calls. This function should be able to accept parameters in the form of an array of elements so that we can use the same common interface as the original. Since then, it has the ability to make chained calls.
The following modifications are as follows:
( function(){ function _$(els){ This. elements = [];//save those elements as arrays in an instance property, for(varI=0, Len=els.length; i<len; i++) {varelement = Els[i];if(typeofelement===' String ') {element = document.getElementById (element); } This. Elements.push (Element); }} _$.prototype = {each: function(FN){ for(varI=0, len= This. elements.length; i<len; i++) {Fn.call ( This, This. Elements[i]); }return This;//In the last return of each method this;}, SetStyle: function(prop, Val){ This. each ( function(EL){El.style[prop] = val; });return This;//In the last return of each method this;}, Show: function(){ varthat = This; This. each ( function(EL){That.setstyle (' Display ',' Block '); });return This;//In the last return of each method this;}, Addevent: function(type, fn){ varAdd = function(EL){ if(Window.addeventlistener) {El.addeventlistener (type, FN,false); }Else if(window.attachevent) {El.addevent (' on '+type, FN); } }; This. each ( function(EL){Add (EL); });return This;//In the last return of each method this;}} window.$ = function(){ return New_$(arguments); }})();
In the last return this, the object that invokes the method is passed to the next method on the call chain.
3. Simulation of jquery bottom-chain programming
//block-level scopes//feature 1 when the program starts, the code executes directly.//feature 2 internal member variables cannot be accessed outside (except for variables without var modifier)( function(window, undefined){ //$ most commonly used objects returned to outside large program development general use ' _ ' as a private object (specification) function _$(arguments){ //Implementation code ... Only the ID selector is implemented here //Regular expression matching ID selector varIdselector =/#\w+/; This. Dom;//This property accepts the resulting element //If Match succeeds accept dom element arguments[0] = ' #inp ' if(Idselector.test (arguments[0])){ This. Dom = document.getElementById (arguments[0].substring (1)); }Else{Throw New Error(' arguments is Error! '); } };//Extend a way to implement chained programming on the function class Function. Prototype.method = function(methodName, fn){ This. prototype[methodname] = fn;return This;//Key to chained programming}//Add some public methods to the prototype object of _$_$.prototype = {constructor: _$, Addevent: function(TYPE,FN){ //give you the Get element register event if(Window.addeventlistener) {//FF This. Dom.addeventlistener (Type, FN); }Else if(window.attachevent) {//IE This. Dom.attachevent (' on '+type, FN); }return This; }, SetStyle: function(prop, Val){ This. dom.style[prop] = val;return This; } };//Window first register a global variable with external relationswindow.$ = _$;//Write a method of preparation_$.onready = function(FN){ //1 instantiation out _$ Object Real Register to windowwindow.$ = function(){ return New_$(arguments); };//2 Execute incoming CodeFN ();//3 for chained programming_$.method (' addevent ', function(){ // nothing to do}). Method (' SetStyle ', function(){ // nothing to do}); };}) (window);//Entry window into the scope of the program$.onready ( function(){ varINP = $ (' #inp ');//alert (inp.dom.nodeName); //alert ($ (' #inp '));Inp.addevent (' click ', function(){Alert' I've been clicked! '); }). SetStyle (' BackgroundColor ',' Red ');});
4. Use callback functions to obtain data from a method that supports chained invocation
Chained calls are well suited to evaluator methods, but it is inconvenient for accessor methods because each method returns this.
However, the workaround is there, and that is the callback function.
When a callback function is not used
//without CallbackWindow. API = window. API | | function(){ varName =' Jchen '; This. SetName = function(newName){name = NewName;return This; }; This. GetName = function(){ returnName };};varo =NewAPI (); Console.log (O.getname ()); Console.log (O.setname (' Haha '). GetName ());
When using callback functions
//with CallbackWindow. API2 = window. API2 | | function(){ varName =' Jchen '; This. SetName = function(newName){name = NewName;return This; }; This. GetName = function(callback){Callback.call ( This, name);return This; };};varO2 =NewAPI2 (); O2.getname (Console.log). SetName (' Hehe '). GetName (Console.log);
When using the callback function Callback.call (this, name) is generally not a problem, but this example is used to Console.log, then there is a problem. The reason is that the this of the console is pointing to console instead of WINODW.
This problem is also very well solved. As follows:
//with CallbackWindow. API2 = window. API2 | | function(){ varName =' Jchen '; This. SetName = function(newName){name = NewName;return This; }; This. GetName = function(callback){Callback.call ( This, name);return This; };};varO2 =NewAPI2 ();varLog = function(para){Console.log (para);};o 2.getName (log). SetName (' Hehe '). GetName (log);
5. Summary
Chaining this style helps simplify code writing, makes your code more concise, easier to read, and avoids reusing an object variable multiple times.
Copyright NOTICE: This article is the original article, reproduced please specify: http://blog.csdn.net/i10630226
JavaScript design mode Item 5-Chained call