jQuery 1.8源码分析 core.js核心模块 jQuery对象的构造分析
2013-05-15 16:34
896 查看
1、init方法详解:
根据上一篇文章的分析,知道init方法其实就是在使用$() 创建jQuery对象是调用的,简单的说其实就是一个元素选择器,在API文档中可以发现,该方法可以提供如下几个用法:
jQuery 的核心功能都是通过这个函数实现的。 jQuery中的一切都基于这个函数,或者说都是在以某种方式使用这个函数。这个函数最基本的用法就是向它传递一个表达式(通常由 CSS 选择器组成),然后根据这个表达式来查找所有匹配的元素。
默认情况下, 如果没有指定context参数,$()将在当前的 HTML document中查找 DOM 元素;如果指定了 context 参数,如一个 DOM 元素集或 jQuery 对象,那就会在这个 context 中查找。在jQuery 1.3.2以后,其返回的元素顺序等同于在context中出现的先后顺序。
参考文档中 选择器 部分获取更多用于 expression 参数的 CSS 语法的信息。
你可以传递一个手写的 HTML 字符串,或者由某些模板引擎或插件创建的字符串,也可以是通过 AJAX 加载过来的字符串。但是在你创建 input 元素的时会有限制,可以参考第二个示例。当然这个字符串可以包含斜杠 (比如一个图像地址),还有反斜杠。当你创建单个元素时,请使用闭合标签或 XHTML 格式。例如,创建一个 span ,可以用$("<span/>") 或 $("<span></span>") ,但不推荐 $("<span>")。在jQuery 中,这个语法等同于$(document.createElement("span")) 。
在jQuery 1.8中,通过$(html,props), 您可以使用任何jQuery对象的方法或插件。在此之前,你只能使用一个方法名的短名单,并有没有成文的方式添加到列表中。现在并不需要是一个列表,在所有!然而,请注意,这可能会导致你的代码的行为改变,如果插件添加后,有相同的名称作为HTML属性。
允许你绑定一个在DOM文档载入完成后执行的函数。这个函数的作用如同$(document).ready()一样,只不过用这个函数时,需要把页面中所有需要在 DOM 加载完成时执行的$()操作符都包装到其中来。从技术上来说,这个函数是可链接的--但真正以这种方式链接的情况并不多。 你可以在一个页面中使用任意多个$(document).ready事件。参考 ready(Function) 获取更多 ready 事件的信息。
为了阅读这个方法,因为里面用到了一个在core.js变量定义部分定义的正则表达式 rquickExpr,所以我们首先来分析一下这个正则表达式的作用。
1.1、init方法中使用的正则表达式:
这里有两个需要强调的正则,如下,其他的自己可以从API文档中找到对应的解释:
分析可以知道,这个正则表达式匹配(<[\w\W]+>)[^>]*或者#([\w-]*))$。
首先看到 (<[\w\W]+>)[^>]* :贪婪模式,最大范围的匹配,例如匹配 <a jksldj >> >>asf12,就是从第一个"<"开始,知道最后一个">",还有后面的非">"字符。
([\w-]*):匹配jQuery中的一个ID,如 #abc
所以这个正则的作用就是匹配传入参数中包含的HTML代码或者元素ID。
1.2、关于该方法编码涉及的一点技巧:
虽然是一个init方法,但是通过各种判断(可以查看代码中HANDLE提示,表示处理了不同的输入请求)以及JS的动态参数特性,为jQuery提供了多种初始化方法。还有一个就是获取到的dom节点的信息都封装到了this数组中,方便循环获取。
1.3、下面是对这个方法代码的解释:
分析代码可知,init方法做了很多个API的实现,比如传入HTML代码创建节点,或者根据id在全局(jQueryRoot)或者指定的范围Context中进行查找。而在指定范围的情况下,调用了jQuery的find() 方法,下面再打开traversing.js中的该方法分析一下:
当我们给$符传递进一个参数(也可能是多个)时,此时它会根据参数的类型(domElement | string | fn | array)进入不同的流程。首先调用正则匹配看是否为创建dom节点的操作,然后看是否为简单id匹配,这一步也由正则匹配完成,否则进入jQuery.fn.find()函数,我们可以打开traversing.js中的该方法分析一下:
其中pushStack()函数的作用是创建一个对象数组,把传入的对象数组也合并进去然后添加到一个栈中,并返回该新建的对象数组:
我们可以看到里面都使用了Sizzle去进行搜索元素,为了探个究竟,我们可以在jQuery的官网http://api.jquery.com/顶部找到Sizzle项目的链接http://sizzlejs.com/ 正如其介绍的,Sizzle是一个纯JavaScript实现的CSS选择器引擎可以方便的嵌入到各种其他的JS类库中用来充当选择器。github上的源代码码下载:https://github.com/jquery/sizzle 这里我们就先跳过这个,看看jQuery的其他模块的,了解整体的架构。
来源于http://www.itzhai.com/jquery-1-8-source-code-analysis-structural-analysis-of-core-js-core-module-jquery-object.html
根据上一篇文章的分析,知道init方法其实就是在使用$() 创建jQuery对象是调用的,简单的说其实就是一个元素选择器,在API文档中可以发现,该方法可以提供如下几个用法:
jQuery([selector,[context]])
概述
这个函数接收一个包含 CSS 选择器的字符串,然后用这个字符串去匹配一组元素。jQuery 的核心功能都是通过这个函数实现的。 jQuery中的一切都基于这个函数,或者说都是在以某种方式使用这个函数。这个函数最基本的用法就是向它传递一个表达式(通常由 CSS 选择器组成),然后根据这个表达式来查找所有匹配的元素。
默认情况下, 如果没有指定context参数,$()将在当前的 HTML document中查找 DOM 元素;如果指定了 context 参数,如一个 DOM 元素集或 jQuery 对象,那就会在这个 context 中查找。在jQuery 1.3.2以后,其返回的元素顺序等同于在context中出现的先后顺序。
参考文档中 选择器 部分获取更多用于 expression 参数的 CSS 语法的信息。
jQuery(html,[ownerDocument]) 返回值:jQuery
概述
根据提供的原始 HTML 标记字符串,动态创建由 jQuery 对象包装的 DOM 元素。同时设置一系列的属性、事件等。你可以传递一个手写的 HTML 字符串,或者由某些模板引擎或插件创建的字符串,也可以是通过 AJAX 加载过来的字符串。但是在你创建 input 元素的时会有限制,可以参考第二个示例。当然这个字符串可以包含斜杠 (比如一个图像地址),还有反斜杠。当你创建单个元素时,请使用闭合标签或 XHTML 格式。例如,创建一个 span ,可以用$("<span/>") 或 $("<span></span>") ,但不推荐 $("<span>")。在jQuery 中,这个语法等同于$(document.createElement("span")) 。
在jQuery 1.8中,通过$(html,props), 您可以使用任何jQuery对象的方法或插件。在此之前,你只能使用一个方法名的短名单,并有没有成文的方式添加到列表中。现在并不需要是一个列表,在所有!然而,请注意,这可能会导致你的代码的行为改变,如果插件添加后,有相同的名称作为HTML属性。
jQuery(callback) 返回值:jQuery
概述
$(document).ready()的简写。允许你绑定一个在DOM文档载入完成后执行的函数。这个函数的作用如同$(document).ready()一样,只不过用这个函数时,需要把页面中所有需要在 DOM 加载完成时执行的$()操作符都包装到其中来。从技术上来说,这个函数是可链接的--但真正以这种方式链接的情况并不多。 你可以在一个页面中使用任意多个$(document).ready事件。参考 ready(Function) 获取更多 ready 事件的信息。
为了阅读这个方法,因为里面用到了一个在core.js变量定义部分定义的正则表达式 rquickExpr,所以我们首先来分析一下这个正则表达式的作用。
1.1、init方法中使用的正则表达式:
rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,
这里有两个需要强调的正则,如下,其他的自己可以从API文档中找到对应的解释:
(?:pattern) 匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分是很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。 x|y 匹配x或y。例如,“z|food”能匹配“z”或“food”。“(z|f)ood”则匹配“zood”或“food”。
分析可以知道,这个正则表达式匹配(<[\w\W]+>)[^>]*或者#([\w-]*))$。
首先看到 (<[\w\W]+>)[^>]* :贪婪模式,最大范围的匹配,例如匹配 <a jksldj >> >>asf12,就是从第一个"<"开始,知道最后一个">",还有后面的非">"字符。
([\w-]*):匹配jQuery中的一个ID,如 #abc
所以这个正则的作用就是匹配传入参数中包含的HTML代码或者元素ID。
1.2、关于该方法编码涉及的一点技巧:
虽然是一个init方法,但是通过各种判断(可以查看代码中HANDLE提示,表示处理了不同的输入请求)以及JS的动态参数特性,为jQuery提供了多种初始化方法。还有一个就是获取到的dom节点的信息都封装到了this数组中,方便循环获取。
1.3、下面是对这个方法代码的解释:
// jQuery对象的初始化方法,实际上就是一个选择器 init: function( selector, context, rootjQuery ) { var match, elem; // HANDLE: $(""), $(null), $(undefined), $(false) if ( !selector ) { // 传入了空,null,undefined或者false的时候,直接返回this引用,没有包含任何节点 return this; } // Handle HTML strings if ( typeof selector === "string" ) { if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { // Assume that strings that start and end with <> are HTML and skip the regex check // 如果是由"<"和">"包裹的HTML则跳过正则匹配,此时是根据传入的HTML创建一个Dom节点 match = [ null, selector, null ]; } else { match = rquickExpr.exec( selector ); } // Match html or make sure no context is specified for #id if ( match && (match[1] || !context) ) { // HANDLE: $(html) -> $(array) if ( match[1] ) { // 根据传入的HTML创建一个Dom节点 context = context instanceof jQuery ? context[0] : context; // scripts is true for back-compat jQuery.merge( this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true ) ); // HANDLE: $(html, props) // 根据传入的 HTML创建Dom节点,并根据传入的context设置prop属性 if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { for ( match in context ) { // Properties of context are called as methods if possible if ( jQuery.isFunction( this[ match ] ) ) { // 如果传入的是函数,则这样赋值,以便可以调用 this[ match ]( context[ match ] ); // ...and otherwise set as attributes } else { // 如果传入的是属性,则这样赋值 this.attr( match, context[ match ] ); } } } return this; // HANDLE: $(#id) 处理传入的是ID的情况 } else { // 根据匹配到的ID使用JS的 getElementById() 方法进行获取元素 elem = document.getElementById( match[2] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 // 6963 bug 处理:处理Blackberry 4.6中返回了一个父节点已经不存在于document中的节点的情况 if ( elem && elem.parentNode ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id !== match[2] ) { return rootjQuery.find( selector ); } // Otherwise, we inject the element directly into the jQuery object this.length = 1; this[0] = elem; } this.context = document; this.selector = selector; return this; } // 下面两个if语句都调用了jQuery的 find() 方法,详细实现参考 traversing.js // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { return ( context || rootjQuery ).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor( context ).find( selector ); } // HANDLE: $(DOMElement) // 传入的是节点类型,直接保存到this数组中返回 } else if ( selector.nodeType ) { this.context = this[0] = selector; this.length = 1; return this; // HANDLE: $(function) // Shortcut for document ready 相当于 $(document).ready() 的缩写 // 传入的是函数,则通过rootjQuery.ready 方法等待执行 } else if ( jQuery.isFunction( selector ) ) { return rootjQuery.ready( selector ); } if ( selector.selector !== undefined ) { this.selector = selector.selector; this.context = selector.context; } return jQuery.makeArray( selector, this ); },
分析代码可知,init方法做了很多个API的实现,比如传入HTML代码创建节点,或者根据id在全局(jQueryRoot)或者指定的范围Context中进行查找。而在指定范围的情况下,调用了jQuery的find() 方法,下面再打开traversing.js中的该方法分析一下:
当我们给$符传递进一个参数(也可能是多个)时,此时它会根据参数的类型(domElement | string | fn | array)进入不同的流程。首先调用正则匹配看是否为创建dom节点的操作,然后看是否为简单id匹配,这一步也由正则匹配完成,否则进入jQuery.fn.find()函数,我们可以打开traversing.js中的该方法分析一下:
find: function( selector ) { var i, ret, self; // 如果传入的不是字符串,即可能是Dom节点或者jQuery对象 if ( typeof selector !== "string" ) { self = this; // 把过滤获取到的匹配元素数组push到堆栈中,并返回这个元素数组 return this.pushStack( jQuery( selector ).filter(function() { for ( i = 0; i < self.length; i++ ) { if ( jQuery.contains( self[ i ], this ) ) { return true; } } }) ); } // 下面是传入的参数selector为字符串的情况 ret = []; for ( i = 0; i < this.length; i++ ) { // 这里调用了jQuery.find方法,详细查看 sizzle-jquery.js文件,定义如下 jQuery.find = Sizzle; // 可见其实现在Sizzle中,可以获取其源代码详细阅读: https://github.com/jquery/sizzle jQuery.find( selector, this[ i ], ret ); } // Needed because $( selector, context ) becomes $( context ).find( selector ) ret = this.pushStack( jQuery.unique( ret ) ); ret.selector = ( this.selector ? this.selector + " " : "" ) + selector; return ret; },
其中pushStack()函数的作用是创建一个对象数组,把传入的对象数组也合并进去然后添加到一个栈中,并返回该新建的对象数组:
// Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack: function( elems ) { // Build a new jQuery matched element set var ret = jQuery.merge( this.constructor(), elems ); // Add the old object onto the stack (as a reference) ret.prevObject = this; ret.context = this.context; // Return the newly-formed element set return ret; },
我们可以看到里面都使用了Sizzle去进行搜索元素,为了探个究竟,我们可以在jQuery的官网http://api.jquery.com/顶部找到Sizzle项目的链接http://sizzlejs.com/ 正如其介绍的,Sizzle是一个纯JavaScript实现的CSS选择器引擎可以方便的嵌入到各种其他的JS类库中用来充当选择器。github上的源代码码下载:https://github.com/jquery/sizzle 这里我们就先跳过这个,看看jQuery的其他模块的,了解整体的架构。
来源于http://www.itzhai.com/jquery-1-8-source-code-analysis-structural-analysis-of-core-js-core-module-jquery-object.html
相关文章推荐
- 源代码阅读方法 jQuery源码解析 核心模块core.js
- 【转】jQuery源码分析-03构造jQuery对象-源码结构和核心函数
- jQuery源码分析-03构造jQuery对象-源码结构和核心函数
- jQuery源码分析-03构造jQuery对象-源码结构和核心函数
- jQuery源码分析(版本1.6.1)___构造jQuery对象-源码结构和核心函数
- jQuery源码分析-03构造jQuery对象-源码结构和核心函数
- jQuery源码分析-构造jQuery对象-源码结构和核心函数
- jQuery核心源码core.js分析
- jQuery核心源码core.js分析
- jquery-1.91.源码分析-2 jquery对象构造
- jQuery源码分析-03构造jQuery对象-工具函数
- jQuery.buildFragment源码分析以及在构造jQuery对象的作用
- jQuery 源码分析和使用心得 - core.js
- 献给和我合作的过得前端童靴们:jquery源码分析--核心函数(包装对象和holdReady方法)
- jQuery源码分析笔记-构造jQuery对象(三)
- jQuery 1.6 源码学习(六)——core.js[6]之jQuery对象/数组操作相关方法
- Three.js源码阅读笔记(基础的核心Core对象)
- jQuery源码分析-03构造jQuery对象-工具函数