方法的链式调用
调用链的结构
对$函数你已经很熟悉了。它通常返回一个html元素或一个html元素的集合,如下:
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; }
但是,如果把这个函数改造为一个构造器,把那些元素作为数组保存在一个实例属性中,并让所有定义在构造器函数的prototype属性所指对象中的方法都返回用以调用方法的那个实例的引用,那么它就具有了链式调用的能力。我首先需要把这个$函数改为一个工厂方法,它负责创建支持链式调用的对象。这个函数应该能接受元素数组形式的参数,以便我们能够使用与原来一样的公用接口。
(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); } })();
由于所有对象都会继承其原型对象的属性和方法,所以我们可以让定义在原型对象中的那几个方法都返回用以调用方法的实例对象的引用,这样就可以对那些方法进行链式调用。想好这一点,我们现在就动手在_$这个私用构造函数的prototype对象中添加方法,以便实现链式调用
(function(){ //use private class function _$(els){ //..省略之前上面的代码 } _$.prototype = { each:function(fn){ for(var i=0,len=this.elements.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); } })();
但是如果某个库或者框架已经定义了一个$函数,那么我们的这个库会将其改写,有个简单的办法是在源码中为$函数另去一个名字。但是如果你是从一个现有的库获得的源码,那么每次代码库获取更新的版本后 你都得重新改名字,因此这个方案并不是很好。好的解决办法就是像下面一样添加一个安装器:
window.installHelper = function(scope, interface) { scope[interface] = function() { return new _$(arguments); } };
用户可以这样去使用:
installHelper(window, ‘$‘); $(‘example‘).show();
下面是一个更复杂的例子,它展示了如何把这种功能添加到一个事先
时间: 2024-11-08 02:53:16