You’re already familiar with the $function. It usually returns an HTML element or a collection of HTML elements as follows:
function$(){ var elements = []; for(vari=0,len=arguments.length; i<len; ++i){ var element = arguments[i]; If (typeof Element === "string"){element = document.getelementById (element); } if(arguments.length==1){ return element; } elements.push(element); } return elements; }Copy the code
However, if you transform this function into a constructor, store those elements as an array in an instance property, and have all the methods defined in the object indicated by the constructor function’s Prototype property return references to the instance in which the method was called, then it has chain-calling capabilities. I first need to change the $function to a factory method that creates objects that support chained calls. This function should accept arguments in the form of an array of elements so that we can use the same common interface as before.
(function(){ //use private class function _$(els){ this.elements = []; for(vari=0,len=els.length; i<len; i++){ var element = els[i]; If (typeof Element === "string"){element = document.getelementById (element); } this.elements.push(element) } } //The public interface remains the same. window.$ = function(){ return new _$(arguments); }}) ();Copy the code
Since all objects inherit the properties and methods of their prototype objects, we can make chain calls to those methods by having all the methods defined in the prototype object return references to the instance object in which the method was called. With this in mind, let’s now add methods to the prototype object of the private constructor _$to make the chain call
(function(){ //use private class function _$(els){ //.. } _$. Prototype = {each:function(fn){for(var I =0,len= this.contact.length; i<len; i++){ fn.call(this,this.elements[i]); } return this; }, show:function(prop,val){ var that = this; This. Each (function (el) {that. SetStyle (" display ", "block"); }); return this; }, addEvent:function(type,fn){ var add = function(el){ if(window.addEventListener){ el.addEventListener(type,fn,false); }else if(window.attachEvent){ el.attachEvent("on"+type,fn); }}; this.each(function(el){ add(el); }); return this; }}; //The public interface remains the same. window.$ = function(){ return new _$(arguments); }}) ();Copy the code
But if a library or framework already defines a $function, our library will rewrite it. An easy way is to give the $function a new name in the source code. But if you get the source code from an existing library, you’ll have to change the name every time the library gets a newer version, so it’s not a very good solution. A good solution is to add an installer as follows:
window.installHelper = function(scope, interface) { scope[interface] = function() { return new _$(arguments); }};Copy the code
Users can use it like this:
installHelper(window, '$');
$('example').show();
Copy the code
Here is a more complex example that shows how to add this functionality to a pre-defined named object:
// Define a namespace without overwriting it if it already exists. window.com = window.com || {}; com.example = com.example || {}; com.example.util = com.example.util || {}; installHelper(com.example.util, 'get'); (function() { var get = com.example.util.get; get('example').addEvent('click', function(e) { get(this).addClass('hello'); }); }) ();Copy the code
Sometimes it’s not a good idea to connect methods. Chained calls are good for evaluator methods, but for evaluator methods, you might want them to return the data you want instead of returning this. However, if you put the chain call as a primary goal, it is hoped that the way of all methods used are consistent, so there is some alternative methods: you can use the callback technology to return to the data of the following two examples: including API class using a common value (it interrupted call chain), while the API2 class USES the callback method:
// Accessor without function callbacks: returning requested data in accessors. window.API = window.API || {}; API.prototype = function() { var name = 'Hello world'; // Privileged mutator method. setName: function(newName) { name = newName; return this; }, // Privileged accessor method. getName: function() { return name; }} (); // Implementation code. var o = new API; console.log(o.getName()); // Displays 'Hello world'. console.log(o.setName('Meow').getName()); // Displays 'Meow'. // Accessor with function callbacks. window.API2 = window.API2 || {}; API2.prototype = function() { var name = 'Hello world'; // Privileged mutator method. setName: function(newName) { name = newName; return this; Function (callback) {callback.call(this, name); // Privileged accessor method. return this; }} (); // Implementation code. var o2 = new API2; o2.getName(console.log).setName('Meow').getName(console.log); // Displays 'Hello world' and then 'Meow'.Copy the code