吃完午饭,觉得有点发困,想起了以后我们的产品可能要做到各种浏览器的兼容于是乎不得不清醒起来!我们的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. wrk 进程管理

    4.3.1 四种情况创建新进程并调用MmInitializeProcessAddressSpace, 调用完这个函数的时候,一个进程的地址空间基本建立了, 可执行文件的映像和ntdll.dll(内存区 ...

  2. 简单几何(直线位置) POJ 1269 Intersecting Lines

    题目传送门 题意:判断两条直线的位置关系,共线或平行或相交 分析:先判断平行还是共线,最后就是相交.平行用叉积判断向量,共线的话也用叉积判断点,相交求交点 /********************* ...

  3. BZOJ3838 : [Pa2013]Raper

    将选取的$A$看成左括号,$B$看成右括号,那么答案是一个合法的括号序列. 那么只要重复取出$k$对价值最小的左右括号,保证每时每刻都是一个合法的括号序列即可. 将$($看成$1$,$)$看成$-1$ ...

  4. BZOJ3322 : [Scoi2013]摩托车交易

    求出最大生成树,则两点间的最大容量为树上两点间的边权的最小值. 设$lim[i]$表示第$i$个订单的城市允许携带的黄金上限,则 $lim[i]=\min(lim[i+1],a[i]和a[i+1]点间 ...

  5. pygame系列_原创百度随心听音乐播放器_完整版

    程序名:PyMusic 解释:pygame+music 之前发布了自己写的小程序:百度随心听音乐播放器的一些效果图 你可以去到这里再次看看效果: pygame系列_百度随心听_完美的UI设计 这个程序 ...

  6. winform学习之----进程和线程

    Process[] pros = Process.GetProcesses();//获取多个进程            foreach(var item in pros)            {   ...

  7. Java递归搜索指定文件夹下的匹配文件

    import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Queue; /** ...

  8. 关于iOS测试机个数上限的详细规则

    关于iOS测试机个数上限的详细规则 前言 公司的iOS测试机快达到苹果规定的100个上限了,而因为the new iPad新出,我们需要新的quota来测试新iPad,所以就仔细研究了一下苹果关于10 ...

  9. Wilddog - 野狗常用知识点

    https://www.wilddog.com/examples/chat-var1 https://z.wilddog.com/web/quickstart 增加或者修改替换整条数据(注意,upda ...

  10. JavaWEB中读取配置信息

    第一种方法是使用java.io和java.util包,缺点是路径的概念要清晰, 例子: Properties prop = new Properties(); InputStream in = get ...