JQuery源码之“对象的结构解析”
吃完午饭,觉得有点发困,想起了以后我们的产品可能要做到各种浏览器的兼容于是乎不得不清醒起来!我们的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源码之“对象的结构解析”的更多相关文章
- 【jQuery源码】事件存储结构
a. jQuery事件原型——Dean Edwards的跨浏览器AddEvent()设计 源码解读 重新梳理一下数据结构,使用一个例子 <input type="text" ...
- jQuery 源码分析(一) 代码结构
jQuery是一个Javascript库,它支持链式操作方式,即对发生在同一个JQuery对象上的一组动作,可以直接接连写无需要重复获取对象.这一特点使得JQuery的代码无比优雅,而且有强大的选择器 ...
- jQuery源码中的“new jQuery.fn.init()”什么意思?
所有文章搬运自我的个人主页:sheilasun.me 引子 最近打算试试看看jQuery的源码,刚开个头就卡住了.无论如何都理解不了jQuery源码入口部分中的 return new jQuery.f ...
- 菜鸟的jQuery源码学习笔记(前言)
前言 相信任何一名前端开发人员或者是前端爱好者都对jQuery不陌生.jQuery简单易用,功能强大,特别是拥有良好的浏览器兼容性,大大降低了前端开发的难度,使得前端开发变得“平易近人起来”.自从本人 ...
- jquery 源码解析
静态与实力方法共享设计 遍历方法 $(".a").each() //作为实例方法存在 $.each() //作为静态方法存在 Jquery源码 jQuery.prototype = ...
- jQuery 源码解析二:jQuery.fn.extend=jQuery.extend 方法探究
终于动笔开始 jQuery 源码解析第二篇,写文章还真是有难度,要把自已懂的表述清楚,要让别人听懂真的不是一见易事. 在 jQuery 源码解析一:jQuery 类库整体架构设计解析 一文,大致描述了 ...
- jQuery源码解析资源便签
最近开始解读jQuery源码,下面的链接都是搜过来的,当然妙味课堂 有相关的一系列视频,长达100多期,就像一只蜗牛慢慢爬, 至少品读三个框架,以后可以打打怪,自己造造轮子. 完全理解jQuery源代 ...
- 【jQuery源码】jQuery对象初始化
看了一下午还是有很多地方没弄明白,jQuery的一些工具方法的原理也不完全清楚,这篇文章会随着我深入阅读jQuery源码的同时不断更新. // Initialize a jQuery object / ...
- 三.jQuery源码解析之jQuery的框架图
这张图片是对jQuery源码截图,一点一点拼出来的. 现在根据这张图片来对jQuery框架做一些说明. 一.16~9404行可以发现,最外层是一个自调用函数.当jQuery初始化时,这个自调用函数包含 ...
随机推荐
- Rightmost Digit
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission( ...
- Spring计划
团队: 郭志豪:http://www.cnblogs.com/gzh13692021053/ 杨子健:http://www.cnblogs.com/yzj666/ 刘森松:http://www.cnb ...
- ZOJ 3157 Weapon
题目传送门 题意:就是CF round# 329 B 的升级版,要求出相交点的个数 分析:逆序数用树状数组维护,求出非逆序数,然后所有情况(n * (n - 1)) / 2减之就是逆序数个数. #in ...
- 简单几何(直线与线段相交) POJ 1039 Pipe
题目传送门 题意:一根管道,有光源从入口发射,问光源最远到达的地方. 分析:黑书上的例题,解法是枚举任意的一个上顶点和一个下顶点(优化后),组成直线,如果直线与所有竖直线段有交点,则表示能穿过管道. ...
- 最短路(Floyd_Warshall) POJ 2253 Frogger
题目传送门 /* 最短路:Floyd算法模板题 */ #include <cstdio> #include <iostream> #include <algorithm& ...
- BZOJ1444 : [Jsoi2009]有趣的游戏
建立AC自动机,并求出转移矩阵. 再用$\sum E(终止节点)=1$去替换第一个方程,高斯消元即可. 时间复杂度$O(n^3l^3)$. 注意精度问题,要特判0.00的情况. #include< ...
- OI优化开关
#pragma comment(linker,"/STACK:10240000,10240000")#pragma GCC optimize ("O2")
- 《菊与刀》--[美]鲁思·本尼迪克特(Ruth Benedict)
<菊与刀>这本书实在是好看. 下面是一些书摘: * 由在美国曾经全力以赴与之战斗的敌人中,日本人的脾气是最琢磨不透的. * “菊”本是日本皇家家微,“刀”是武家文化的象征. * 日本人的格 ...
- MyEclipse设置注释格式(转载)
Window --> Java --> Code Style --> Code Templates --> Comments --> types --> Edit ...
- ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES) ERROR 2013 (HY00 ...