jQuery插件接口的实现,jquery.extend
http://www.imooc.com/code/3403
如果jQuery没有插件接口的设计,那么他就像个光杆司令没有兵,就是没有手下,只有自己一个封闭的城堡。因此jQuery城堡需要设计一个大门 - 插件接口,从而打开大门开始招兵买马。当然jQuery除了获得“开发者社区”的大力支持外,也有很多大公司纷纷对它投出了橄榄枝,这也是它成功的关键。
基于插件接口设计的好处也是颇多的,其中一个最重要的好处是把扩展的功能从主体框架中剥离出去,降低了框架的复杂度。接口的设计好比电脑上的配件如:CPU、内存、硬盘都是作为独立的模块分离出去了,但是主板提供模块的接口,例如支持串口的硬盘,我只要这个硬盘的接口能插上,甭管是500G还是1000G的容量的硬盘,都能使用。所以在软件设计中插件接口的提供把独立的功能与框架以一种很宽松的方式松耦合。
从之前的分析中我们可以知道jQuery对象的原理,所以一般来说,jQuery插件的开发分为两种:
☑ 一种是挂在jQuery命名空间下的全局函数,也可称为静态方法; ☑ 另一种是jQuery对象级别的方法,即挂在jQuery原型下的方法,这样通过选择器获取的jQuery对象实例也能共享该方法。
分别是$.fn.extend()和$.extend()
//一个参数:$.extend()和$.fn.extend() 不一样 $.extend({ fn1: function(){ console.log("fn1"); } }); $.fn1();//fn1,加的实例方法 $.fn.extend({ fn2: function(){ console.log("fn2"); } }); var div = $("#Odiv"); div.fn2();//fn2,加的静态方法 //多个参数:复制,$.extend和$.fn.extend是一样的 $.extend({name:"ss"},{age:11}) Object {name: "ss", age: 11} $.fn.extend({name:"ss"},{age:11}) Object {name: "ss", age: 11}
简单来讲这样实现:
ajQuery.extend = ajQuery.fn.extend = function() { var options, src, copy, target = arguments[0] || {}, i = 1, length = arguments.length; //只有一个参数,就是对jQuery自身的扩展处理 //extend,fn.extend if (i === length) { target = this; //调用的上下文对象jQuery/或者实例 i--; } for (; i < length; i++) { //从i开始取参数,不为空开始遍历 if ((options = arguments[i]) != null) { for (name in options) { copy = options[name]; //覆盖拷贝 target[name] = copy; } } } return target; }
浅复制
var obj1 = {name:{name1:"s1",name2:"s2"},age:12}; var obj2 = {}; for(var i in obj1){ obj2[i] = obj1[i]; } console.log(obj2);//obj1.name === obj2.name
$.extend(false,{A},{B}):浅复制,批向相同的引用,把B中的对象或者值给A即可,无关递归。
$.extend(true,{A},{B}):深复制,得到一个新的对象,和原来的对象没有关系。B中的对象要通过递归得到新的对象给A。
extend jQuery实现:
var $$ = ajQuery = function(selector) { //把原型上的init作为构造器 return new ajQuery.fn.init( selector ); } ajQuery.fn = ajQuery.prototype = { name: 'aaron', init: function(selector) { this.selector = selector; return this; }, constructor: ajQuery } ajQuery.fn.init.prototype = ajQuery.fn; ajQuery.extend = ajQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; // Handle a deep copy situation if ( typeof target === "boolean" ) { deep = target; // skip the boolean and the target target = arguments[ i ] || {}; i++; } // Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // extend jQuery itself if only one argument is passed if ( i === length ) { target = this; i--; } for ( ; i < length; i++ ) { // Only deal with non-null/undefined values if ( (options = arguments[ i ]) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ];//bb // Prevent never-ending loop if ( target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { if ( copyIsArray ) { //数组深复制 copyIsArray = false; clone = src && jQuery.isArray(src) ? src : []; } else { //对象深复制 clone = src && jQuery.isPlainObject(src) ? src : {}; } // Never move original objects, clone them //递归实现深复制 target[ name ] = ajQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { //浅复制:指向同样的地址 target[ name ] = copy; } } } } // Return the modified object return target; }; var aa = {a:"aaaa"}; ajQuery.extend(true,aa,{b:"bb",c:{c1:"c111",c2:"c222"}});