【jQuery-1.7.2源码分析】extend
上一篇说的jQ对象的鸟瞰图,这还是一个非常简单的对象,jQ强大的各种方法则是通过各种扩展实现的。
jQ的扩展分两种
1. 把相对紧凑的方法统一在一处,因此,在内部写法上看起来是一个个的模块,这样便于维护。其中分为两类:
1) 基于jQuery这个对象,也就是静态属性/方法的作用,这部分的扩展更为通用,比如 attr: function( elem, name, value, pass ),脱离jQ对象也可以使用
2) 基于 prototype 的,内部大多只是借用了静态属性/方法
2. 当作工具方法
如需要给obj = {a:1, b:2}对象加几个属性,就直接obj = jQuery.extend(obj, {})
这部分没啥好说的,就一个方法,而且不长,我不打算贴原版代码,因为我觉得凡是jQ的写法都要批判着看,它的确功能强大,但不代表连带它的代码风格都要推广。
下面给出我的版本,如果需要原版,请自行下载。
// 关于这个方法的形参,我个人认为使这样的: // 如果是 extend(<1>),表示给jQ对象扩展<1>的功能 // 如果是 extend(<0>, <1>), 则表示给<0>扩展<1>的功能 // // 需要提醒一下,<1>不仅可以是一个{},还可以是多个{},即扩展多种功能 // 除此之外,第一个参数还可以是boolean,表示是否深拷贝,这样的话 // 剩下的参数都要往后移一位 jQuery.extend = jQuery.fn.extend = function() { // 默认的处理是理想情况,即extend(<0>, <1>) var target = arguments[0], // target 表示给谁扩展 deep = false, // 是否需要深拷贝, 默认不需要 i = 1; // i表示扩展的部分从第几个参数开始 if (typeof target === 'boolean') { // 指定是否需要深拷贝 deep = target; // 移位 target = arguments[1]; i = 2; } // 到这里因为已经确定了target // 所以需要判断一下target是否合法 if (typeof target !== 'object' && !jQuery.isFunction(target)) { target = {}; } var length = arguments.length; // 不存在<1>的情况,也就是扩展目标是jQ对象 if (length === i) { // 再次移位 target = this; i--; } var options, name, src, copy, copyIsArray, clone; for (; i < length; i++) { if ((options = arguments[i]) != null) { // options也可以是数组哦 for (name in options) { src = target[name]; copy = options[name]; // 如果相等会出现死循环 if (target === copy) { continue; } // 深拷贝就是去递归 if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) { // 这里需要保证是同类型的拷贝,即 object > object, array > array if (copyIsArray) { // 重置,不然的话,如果jQuery.isPlainObject(copy)为true会出问题 copyIsArray = false; clone = src && jQuery.isArray(src) ? src : []; } else { clone = src && jQuery.isPlainObject(src) ? src : {}; } // 这次扩展的目标就不是jQ对象了,而是clone target[name] = jQuery.extend(deep, clone, copy); // 我觉得copy不可能出现 undefined 吧 // 除非是 {key: undefined} 这么写代码真是够蛋疼的 } else if (copy !== 'undefined') { target[name] = copy; } } } } return target; };
技巧:
1. 数组也可以用for in,这时 key 是数组索引
var arr = [1, 2, 3, 4]; for (var key in arr) { console.log(key); }
注意:关于 for in 是否有序,参考 w3help。
只要 object 的 key 没有数字,遍历顺序和定义顺序是相同的;
如果有数字,会先把数字排好序,然后才是非数字部分,遍历顺序也是先数字,后非数字