JavaScript Design Pattern Item 5 -- chained call
1. What is chain call?
This is easy to understand, for example:
$(this).setStyle('color', 'red').show();
The difference between a common function call and a chain call: After a method is called,return thisReturns the object of the currently called method.
Function Dog () {this. run = function () {alert (The dog is running ....); return this; // return the current object Dog}; this. eat = function () {alert (After running the dog is eatting ....); return this; // return the current object Dog}; this. sleep = function () {alert (After eatting the dog is running ....); return this; // return the current object Dog};} // general call method;/* var dog1 = new Dog (); dog1.run (); dog1.eat (); dog1.sleep (); */var dog2 = new Dog (); dog2.run (). eat (). sleep ();
2. Break down chain calls
Chain call is actually two parts:
1.Operation object(That is, the operated DOM element, $ (this) in the above example ))
2.Procedure(What to do, setStyle and show in the above example)
How to Implement operation objects and Methods
Create a common $ function:
function $(){ var elements = []; for(var i= 0,len=arguments.length; i
However, if you transform this function into a constructor and save those elements as arrays in an instance attribute, and let all the methods defined in the prototype attribute of the constructor function return the reference of the Instance used to call the method, then it has the ability of chain call. (Once said so, it is at the end of each method.return this;),
First, I need$The function is changed 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 element arrays so that we can use the same public interface as the original one. In this way, it has the ability to perform chained calls.
The transformation is as follows:
(Function () {function _ $ (els) {this. elements = []; // save those elements as an array in an instance attribute, for (var I = 0, len = els. length; I
Return this at the end, which passes the object of the called Method to the next method on the call chain.
3. Simulate jquery underlying chain Programming
// Block-level scope // feature 1 the code in the program is directly executed when it is started // Feature 2 the internal member variables cannot be accessed externally (except for variables without var modification) (function (window, undefined) {// $ return the most common objects to external large-scale program development. Generally, '_' is used as the private object (specification) function _ $ (arguments) {// implementation code... here we only implement ID selector // Regular Expression matching id selector var idselector =/# w +/; this. dom; // This property accepts the obtained element // if the match is successful, the dom element arguments [0] = '# input' if (idselector. test (arguments [0]) {this. dom = document. getElementById (arguments [0]. substring (1);} else {Throw new Error ('arguments is error! ') ;}}; // Extend a Function in the Function class to implement chained programming. prototype. method = function (methodName, fn) {this. prototype [methodName] = fn; return this; // key to chained programming} // Add some common methods on the _ $ prototype object _ $. prototype = {constructor: _ $, addEvent: function (type, fn) {// register the 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 ;}; // register a global variable on the window to generate a relationship with the outside world. window. $ =_$; // write a preparation method _ $. onReady = function (fn) {// 1 instantiate it. $ = function () {return new _ $ (arguments) ;}; // 2 run the incoming code fn (); // 3 implement chained programming _ $. method ('addevent', function () {// nothing to do }). method ('setstyle', function () {// nothing to do}) ;}}) (Window); // the program's entry window is passed into the scope $. onReady (function () {var indium =$ ('# input'); // alert (Indium. dom. nodeName); // alert ($ ('# input'); indium. addEvent ('click', function () {alert ('I have been clicked! ') ;}). SetStyle ('backgroundcolor', 'red ');});
4. Use the callback function to obtain data from methods that support chained calls
Chained call is very suitable for the value assignment method, but it is inconvenient for the value assignment method, because every method returns this.
However, there are some work ing methods, that is, the callback function.
When callback function is not used
//without callbackwindow.API = window.API || function(){ var name = 'JChen'; this.setName = function(newName){ name = newName; return this; }; this.getName = function(){ return name; };};var o = new API();console.log(o.getName());console.log(o.setName('Haha').getName());
When using callback Functions
//with callbackwindow.API2 = window.API2 || function(){ var name = 'JChen'; this.setName = function(newName){ name = newName; return this; }; this.getName = function(callback){ callback.call(this, name); return this; };};var o2 = new API2();o2.getName(console.log).setName('Hehe').getName(console.log);
When using the callback function, callback. call (this, name) is normal. However, the console. log is used in this example, so there is a problem. The reason is that this in the console directs to the console rather than winodw.
This problem is also well solved. As follows:
//with callbackwindow.API2 = window.API2 || function(){ var name = 'JChen'; this.setName = function(newName){ name = newName; return this; }; this.getName = function(callback){ callback.call(this, name); return this; };};var o2 = new API2();var log = function(para){ console.log(para);};o2.getName(log).setName('Hehe').getName(log);
5. Summary
The chain call style helps simplify code writing, make the code more concise and easy to read, and avoid repeated use of an object variable multiple times.