jQuery技术

jQuery1.9.1--结构及$方法的工作原理源码分析(2)

字号+ 作者:H5之家 来源:H5之家 2017-08-11 18:00 我要评论( )

看完了init构造函数大概知道了$方法的多样式原来是这样来的,这么多条件判断。现在我们仅仅知道$()方法是怎么判断参数,却对生成的相应的元素集原理很模糊。我们还是以$('div')为例,当被实例化后会执行到这个分支

  看完了init构造函数大概知道了$方法的多样式原来是这样来的,这么多条件判断。现在我们仅仅知道$()方法是怎么判断参数,却对生成的相应的元素集原理很模糊。我们还是以$('div')为例,当被实例化后会执行到这个分支的内容:

return (context || rootjQuery).find(selector);

这里调用了jQuery.fn.find方法,让我们来看看该部分的源码:

find: function (selector) { var i, ret, self, len = this.length; if (typeof selector !== 'string') { self = this; return this.pushStack(jQuery(selector).filter(function () { for (i = 0; i < len; i++) { if (jQuery.contains(self[i], this)) { return true; } } })); } ret = []; for (i = 0; i < len; i++) { jQuery.find(selector, this[i], ret); } // Needed because $( selector, context ) becomes $( context ).find( selector ) ret = this.pushStack(len > 1 ? jQuery.unique(ret) : ret); ret.selector = (this.selector ? this.selector + ' ' : '') + selector; return ret; }

  代码比较简单,没怎么注释,这里遍历jQuery元素集然后使用jQuery.find静态方法(同时也就是Sizzle方法),先暂时不讲解Sizzle选择器的工作原理,因为这不是一个篇幅可以讲完的事。Sizzle方法会将匹配到的元素数组返回给ret。此时ret已经有了我们希望操作的元素了,接下来要给实例对象添加数组特性和context, selector属性。jQuery.fn.pushStack方法会新实例化一个jQuery对象,并且合并元素到该新实例化对象中,再给新实例对象添加prevObject(保存着当前实例化对象的引用,非新实例化对象)和context属性

// 使用传入的元素生成一个新的jQuery元素,( // 将元素数组合并到this对象中) // 并将这个对象的prevObject设置成当 // 前这个实例对象(this).最后将这个新生成的jQuery对象返回 // 把当前的jQuery对象缓存起来, // 以便以后使用end方法恢复这个jQuery对象 pushStack: function (elems) { // 新建一个新的jQuery匹配元素集 // this.constructor === jQuery // jQuery()返回的是this // 通过将elems数组merge到this中,使this也具有类似数组的特性, // 这就是使用选择器匹配到的元素被合并到this中的原因 var ret = jQuery.merge(this.constructor(), elems); // 把旧对象保存在prevObject属性上 ret.prevObject = this; ret.context = this.context; // 返回新的元素集 return ret; }

  jQuery.merge:

/** * 合并两个数组(或类数组) * 返回合并后的第一个内容 */ merge: function (first, second) { var l = second.length, i = first.length, j = 0; if (typeof l === 'number') { for (; j < l; j++) { first[i++] = second[j]; } } else { while (second[j] !== undefined) { first[i++] = second[j++]; } } first.length = i; return first; }

  

至此我们的$方法已经获取了我们希望匹配的元素了,那么是怎么使用jQuery的其他方法的呢?

// 延迟实例化 /* 这里将init的构造函数原型指向jQuery.fn(即jQuery原型), 当我们给jQuery.fn扩展方法或属性的时候,实际上就是给init.prototype, 而jQuery()方法返回的是init构造函数的实例化对象,所以jQuery()就是其实例对象, 具有了其方法和属性。 */ jQuery.fn.init.prototype = jQuery.fn;

  此时我们就可以使用jQuery.fn中的方法了,为了简便扩展方法,jQuery用了extend方法:

/* 用一个或多个其他对象来扩展一个对象,返回被扩展的对象 */ // jQuery.extend(target, [object1], [objectN]) // jQuery.extend([deep], target, object1, [objectN]) // jQuery.fn.extend就是jQuery.fn.init.prototype.extend, // 所以this就是init的实例化对象,即jQuery(..) jQuery.extend = jQuery.fn.extend = function () { var src, copyIsArray, copy, name, options, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; // 处理 深拷贝的情况 if (typeof target === 'boolean') { deep = target; target = arguments[1] || {}; // 略过布尔值 i = 2; } // target非对象或函数则强制转换为空对象 if (typeof target !== 'object' && !jQuery.isFunction(target)) { target = {}; } // 当只有一个参数或者深度拷贝的两个参数时说明是扩展jQuery或者jQuery.fn if (length === i) { target = this; --i; } for (; i < length; i++) { if ((options = arguments[i]) != null) { for (name in options) { src = target[name]; copy = options[name]; // 避免循环递归, 不把自己的引用作为自己的一个成员 if (target === copy) { continue; } // 递归深度拷贝的对象或数组 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 : {}; } // 递归调用 target[name] = jQuery.extend(deep, clone, copy); } else if (copy !== undefined) { target[name] = copy; } } } } // 返回被修改的对象 return target; }

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • jQuery插件开发入门 WEB前端开发

    jQuery插件开发入门 WEB前端开发

    2017-08-11 13:00

  • 轻松学习jQuery插件EasyUI EasyUI实现树形网络基本操作(2)

    轻松学习jQuery插件EasyUI EasyUI实现树形网络基本操作(2)

    2017-08-11 12:00

  • jQuery EasyUI网络教程 pdf

    jQuery EasyUI网络教程 pdf

    2017-08-10 11:00

  • 详解JQuery全部选择器

    详解JQuery全部选择器

    2017-08-09 16:00

网友点评