吃完午饭,觉得有点发困,想起了以后我们的产品可能要做到各种浏览器的兼容于是乎不得不清醒起来!我们的web项目多数是依赖于Jquery的。据了解,在Jquery的2.0版本以后对IE的低端版本浏览器不再支持(IE 5,6,7,8)这样我们要做到兼容的话可能要调整当前jquery中的源代码。我使用NuGet中安装了最新的2.1.4版本。我们在项目中最最熟悉的就是使用JQ的选择器($(...)),说做就做,马上给大家简单粗矿的解释下。

  那么我们常用的大概是这样几种形式:

$("#ID")
$(".Class")
$("<div></div>")
$("div")
$(this)

那么在之前我的文章中已经交代了$(...)是如何获得到当前对象后能够调用到自己的方法,在这里不多说。

Jquery是在它原型链的init()方法中将参数传入,代码如下:

var
// Use the correct document accordingly with window argument (sandbox)
document = window.document, version = "2.1.4", // Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
// Need init if jQuery is called (just allow error to be thrown if not included)
return new jQuery.fn.init( selector, context );
},

  那么继续向下看,在Jquery 2.1.4源码中第2735行看到了init中的实现过程。

   如果在JQ的选择器中你给定格式是下面的几种,如$(""), $(null), $(undefined), $(false)那么JQ就直接将直接return this;不会执行接下来的操作。

那么参数如果是第一个代码块中的形式并且为字符串则执行如下代码:

    if ( typeof selector === "string" ) {
if ( selector[0] === "<" && selector[ selector.length - 1 ] === ">" && selector.length >= 3 ) {
// Assume that strings that start and end with <> are HTML and skip the regex check
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) ) { if ( match[1] ) {
context = context instanceof jQuery ? context[0] : context; jQuery.merge( this, jQuery.parseHTML(
match[1],
context && context.nodeType ? context.ownerDocument || context : document,
true
) );//....未全部列出

  首先来看match 是在init的开始阶段声明的变量,目的就是来记录当前JQ传入的参数。

  1.如果进入这个分支->if ( selector[0] === "<" && selector[ selector.length - 1 ] === ">" && selector.length >= 3 ) {

那么JQ的选择器中传入的就是标签的形式如:$("<div></div>"),所以match应该就是这种结构:match = [ null, <div></div>, null ];。

  2.如果跳到else中则执行:

   match = rquickExpr.exec( selector );

   rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,

显而易见,这样处理之后selector满足如$("#oo")这种形式,那么match = [ "#div", null, "div"];。

  3.如果非以上两种形式那么可能为$(".Class")或更复杂的选择器,这样match就会返回null。

***如果对此有问题,则正则表达式的exec方法***

  接下来我们继续关注Jquery 2.1.4源码中第2785行:

                } else {
elem = document.getElementById( match[2] ); if ( elem && elem.parentNode ) {
// Inject the element directly into the jQuery object
this.length = 1;
this[0] = elem;
} this.context = document;
this.selector = selector;
return this;
}

这是 if(match[1]) {的else分支,观察上下文可知这段else就是处理$("#oo")这种形式,通过Id找到对象并返回,简单的原生JS很好理解。接下来让我们的目光转向if(match[1])中的处理。代码如下:

    context = context instanceof jQuery ? context[0] : context;
jQuery.merge( this, jQuery.parseHTML(
match[1],
context && context.nodeType ? context.ownerDocument || context : document,
true
) ); // HANDLE: $(html, props)
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;

这段代码就是为传入参数为Dom节点工作的,作为一个前端的程序员,我们对$的merge方法再熟悉不过了,它在外部暴漏的功能就是合并数组;那么向下请仔细看它却可以合并JSON。我们先暂时不理会它为什么要合并JSON,先考虑这样一个问题,代码如下:

 $("span").css("background","red");

也许要是你来实现,你一定会这样想,很简单的创建两个span标签然后循环遍历后改变css属性。代码的实现大致是这样:

for(;i<xxx.length;i++){
xxx[i].style.background = "red";
}

但是看了$("span")对象结构后我却十分惊奇,JQuery竟然遍历的是一个JS对象(JSON),我们都知道JS对象是不能遍历的,但如果我们把对象的属性设置为特殊的形式那么就让遍历成为了可能,代码如下:

this={
0:span,
1:span,
2:span,
length:3
} for(;i<this.length;i++){
this[i]//
}

到这里大家是不是觉得眼前一亮,JQuery巧妙的运用了语言结构,来实现这里并最后将对象返回再去调用其它方法,真是做的十分给力。镜头拉回来让我们看看$.merge()中的处理:

        jQuery.merge( this, jQuery.parseHTML(
match[1],
context && context.nodeType ? context.ownerDocument || context : document,
true
) );

这里meger()方法的功能就是将$.parseHTML()方法生成的数组合并到this的JSON中去。而parseHTML的第三个参数true以将HTML脚本标签添加到组中并生效。

1.***第二个参数如果传入为空那么就是当前的文档document,当然也可以是iframe***

2.***meger和parseHTML方法的实现,以后有时间会继续讲解***

  最后让我们看下 if(match[1])中的最后处理,代码如下:

    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 ] );
}
}
}

$("<span>1</span>", { id: 123, style: "" });

针对上面<span>1</span>标签例子,Jquery约定第一个string参数为单标签,第二为对象参数那么就会进入上面的代码块中将对象中提到的属性加入到该对象标签中。

至于为什么是单标签可以在rsingleTag指向的正则表达式中找到答案。

到了这里我并没有觉得松了一口气,却因初涉Jquery源码被其的“博大精深”把心提到了“嗓子眼”啊。以后有机希望能够继续给朋友们分享Jquery的“灵魂”,以上内容如有错误之处请各位大侠果断指出,小弟不胜感激!么么哒。

JQuery源码之“对象的结构解析”的更多相关文章

  1. 【jQuery源码】事件存储结构

    a. jQuery事件原型——Dean Edwards的跨浏览器AddEvent()设计 源码解读   重新梳理一下数据结构,使用一个例子 <input type="text" ...

  2. jQuery 源码分析(一) 代码结构

    jQuery是一个Javascript库,它支持链式操作方式,即对发生在同一个JQuery对象上的一组动作,可以直接接连写无需要重复获取对象.这一特点使得JQuery的代码无比优雅,而且有强大的选择器 ...

  3. jQuery源码中的“new jQuery.fn.init()”什么意思?

    所有文章搬运自我的个人主页:sheilasun.me 引子 最近打算试试看看jQuery的源码,刚开个头就卡住了.无论如何都理解不了jQuery源码入口部分中的 return new jQuery.f ...

  4. 菜鸟的jQuery源码学习笔记(前言)

    前言 相信任何一名前端开发人员或者是前端爱好者都对jQuery不陌生.jQuery简单易用,功能强大,特别是拥有良好的浏览器兼容性,大大降低了前端开发的难度,使得前端开发变得“平易近人起来”.自从本人 ...

  5. jquery 源码解析

    静态与实力方法共享设计 遍历方法 $(".a").each() //作为实例方法存在 $.each() //作为静态方法存在 Jquery源码 jQuery.prototype = ...

  6. jQuery 源码解析二:jQuery.fn.extend=jQuery.extend 方法探究

    终于动笔开始 jQuery 源码解析第二篇,写文章还真是有难度,要把自已懂的表述清楚,要让别人听懂真的不是一见易事. 在 jQuery 源码解析一:jQuery 类库整体架构设计解析 一文,大致描述了 ...

  7. jQuery源码解析资源便签

    最近开始解读jQuery源码,下面的链接都是搜过来的,当然妙味课堂 有相关的一系列视频,长达100多期,就像一只蜗牛慢慢爬, 至少品读三个框架,以后可以打打怪,自己造造轮子. 完全理解jQuery源代 ...

  8. 【jQuery源码】jQuery对象初始化

    看了一下午还是有很多地方没弄明白,jQuery的一些工具方法的原理也不完全清楚,这篇文章会随着我深入阅读jQuery源码的同时不断更新. // Initialize a jQuery object / ...

  9. 三.jQuery源码解析之jQuery的框架图

    这张图片是对jQuery源码截图,一点一点拼出来的. 现在根据这张图片来对jQuery框架做一些说明. 一.16~9404行可以发现,最外层是一个自调用函数.当jQuery初始化时,这个自调用函数包含 ...

随机推荐

  1. BZOJ1695 : [Usaco2007 Demo]Walk the Talk

    观察单词表可以发现: 对于长度为3的单词,前两个字母相同的单词不超过7个 对于长度为4的单词,前两个字母相同的单词不超过35个 于是首先$O(26*26*nm)$预处理出 s1[x][i][j]表示( ...

  2. 洛谷 P1147 连续自然数和 Label:等差数列

    题目描述 对一个给定的自然数M,求出所有的连续的自然数段,这些连续的自然数段中的全部数之和为M. 例子:1998+1999+2000+2001+2002 = 10000,所以从1998到2002的一个 ...

  3. 【POJ】2187 Beauty Contest(旋转卡壳)

    http://poj.org/problem?id=2187 显然直径在凸包上(黑书上有证明).(然后这题让我发现我之前好几次凸包的排序都错了QAQ只排序了x轴.....没有排序y轴.. 然后本题数据 ...

  4. WordPress折腾日记

    安装环境: 我开了个虚拟机xp....用xampp的整合包..下载地址https://www.apachefriends.org/zh_cn/download.html 跟着安装就行了.最后打开xam ...

  5. Java_解决java.security.cert.CertificateException: Certificates does not conform to algorithm constraints

    找到 jre/lib/security/java.security 将 jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048 ...

  6. oracle中用SQL实现两个日期间的日期形成一个数据集

    比如输入2014-06-1 和 2014-07-1形成一个2014-06-1 2014-06-22014-06-3...2014-07-1 的数据集.   解决方法: select date'2014 ...

  7. SQL server 表中如何创建索引?

    SQL server 表中如何创建索引?看个示例,你就会了 use master goif db_id(N'zhangxu')is not nulldrop database zhangxugocre ...

  8. 【C语言】08-数组

    为了让大家更好地学习和理解数组,我们先来认识一下内存中的"地址". 地址 1.计算机中的内存是以字节为单位的存储空间.内存的每一个字节都有一个唯一的编号,这个编号就称为地址.凡存放 ...

  9. Grasshopper 2.0 MP Color FireWire 1394b (Sony ICX274)

        相机参数如下,参见这里: Resolution 1624 x 1224 Frame Rate 30 FPS Megapixels 2.0 MP Chroma Color Sensor Name ...

  10. float塌陷有关问题

    程序代码需要用到的CSS样式body{ margin:0px; padding:0px; text-align:center; font:Arial, Helvetica, sans-serif; f ...