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

    做柔性体仿真,从ANSYS导入模态中性文件时有这个报错. Negative pivot encountered. This is  likely caused by insufficient disp ...

  2. win8 中实现断点续传

    1) Resume method does resume on cases where resume is possible. Meaning if the server accepts range- ...

  3. Codeforces Round #213 (Div. 2) B. The Fibonacci Segment

    #include <iostream> #include <algorithm> #include <vector> using namespace std; in ...

  4. xubuntu12.04配置

    更改源:我用上海交通大学的 首先备份Ubuntu12.04源列表sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup   #(备份下当前 ...

  5. 【wikioi】1922 骑士共存问题(网络流/二分图匹配)

    用匈牙利tle啊喂?和网络流不都是n^3的吗(匈牙利O(nm), isap O(n^2m) 但是isap实际复杂度很优的(二分图匹配中,dinic是O(sqrt(V)*E),不知道isap是不是一样. ...

  6. 【Vijos】1431 守望者的逃离

    题目链接:https://vijos.org/p/1431 算法:贪心 描述 恶魔猎手尤迪安野心勃勃,他背叛了暗夜精灵,率领深藏在海底的娜迦族企图叛变.守望者在与尤迪安的交锋中遭遇了围杀,被困在一个荒 ...

  7. Google Code Jam 2009 Qualification Round Problem C. Welcome to Code Jam

    本题的 Large dataset 本人尚未解决. https://code.google.com/codejam/contest/90101/dashboard#s=p2 Problem So yo ...

  8. Android 通用流行框架大全

    1. 缓存 DiskLruCache    Java实现基于LRU的磁盘缓存 2.图片加载 Android Universal Image Loader 一个强大的加载,缓存,展示图片的库 Picas ...

  9. Editplus从下载到使用

    ☆ 准备工作 1,保证浏览器正常上网 2,能下载软件或已经下载到Editplus这个工具. ☆ 下载editplus 在浏览器输入http://www.editplus.com,然后回车.进入edit ...

  10. MySQL5.7安装过程以及参数和设置说明

    最近在讲MySQL课程,为了省事就在用MySQL5.5版本.因为win10不论32还是64都可以运行MySQL32位.可有很多使用者了解MySQL官网之后,去下载最新版的MySQL来使用,这点我不反对 ...