[No.8 jQuery源码解析—逐段解析
Posted 烟雨风飘渺
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[No.8 jQuery源码解析—逐段解析相关的知识,希望对你有一定的参考价值。
继续咱们的jQuery源码解析。
(function(){
(96 , 283) 给JQ对象,添加一些方法和属性
(285 , 347) extend : JQ的继承方法
(349 , 817) jQuery.extend() : 扩展一些工具方法
(877 , 2856) Sizzle : 复杂选择器的实现
(2880 , 3042) Callbacks : 回调对象 : 对函数的统一管理
(3043 , 3183) Deferred : 延迟对象 : 对异步的统一管理
(3184 , 3295) support : 功能检测
(3308 , 3652) data() : 数据缓存
(3653 , 3797) queue() : 队列方法 : 执行顺序的管理
(3803 , 4299) attr() prop() val() addClass()等 : 对元素属性的操作
(4300 , 5128) on() trigger() : 事件操作的相关方法
(5140 , 6057) DOM操作 : 添加 删除 获取 包装 DOM筛选
(6058 , 6620) css() : 样式的操作
(6621 , 7854) 提交的数据和ajax() : ajax() load() getJSON()
(7855 , 8584) animate() : 运动的方法
(8585 , 8792) offset() : 位置和尺寸的方法
(8804 , 8821) JQ支持模块化的模式
(8826) window.jQuery = window.$ = jQuery;
})();
咱们继续讲jQuery源码,
讲之前,我先帮大家复习下之前的内容,
在之前我们讲到的是第二个部分,
给jQuery对象添加一些常见的方法和属性,
在这部分我给大家做了更细致的划分,
<script>
jQuery.fn = jQuery.prototype{ // 添加实例属性和方法
jQuery:版本
constructor:修正指向问题
init():初始化和参数管理
selector:存储选择字符串
length:this对象的长度
toArray():this对象的长度
get():转原生集合
pushStack():JQ对象的入栈
each():遍历集合
ready():DOM加载的接口
slice():集合的截取
first():集合的第一项
last():集合的最后一项
eq():集合的指定项
map():返回集合前一个状态
push():(内部使用)
sort():(内部使用)
splice():(内部使用)
}
</script>
咱们讲到了这个init,
它是初始化和参数管理,
在init当中我们可以做哪些事情,
就是可以给jQuery传不同类型的参数,
我们我讲过它可以空,undefined,
false,该怎么处理,
或者在jQuery当中传字符串的时候,
该怎么处理。
后面还有对象啊函数该怎么处理,
我们来看一眼jQuery源码,
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
var match, elem;
......
在这个init当中我们可以发现,
在处理字符串的时候,
这里面的嵌套比较多,
所以说我们先看一下,
如果走if的话,肯定是字符串类型,
在这if当中,它又走了个if..else的判断,
if ( match && (match[1] || !context) ) {
这个if走的是创建标签和id的形式,
进来之后又做了一个if,
if ( match[1] ) {
这个if就是创建标签,
而它所对应的else是id的操作形式。
// HANDLE: $(#id)
} else {
elem = document.getElementById( match[2] );
我们上次就讲到这里,
接下来我们看一下这个id该怎么处理,
在这个id的时候,我们可以看到第一句话,
就是通过原生的getELementById这个方法,
来获取到这个id的元素
接下来,我们看一下match[2]里面存的是什么,
前面我帮大家分析过,如果是id的形式,
math这个数组,会长成什么样。
math = ['#div1',null,'div1'];
可以发现这个下标为2的是不是就是这个div1,
所以源码当中这里正好是选到我们想要的id,
存成了一个元素,存成了元素之后,
我们可以看到下面有两段注释,
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
这两段注释是什么意思?
其实是这样的,
所有浏览器去判断这个元素存不存在,
就知道我们这个获取的id对不对,
但是有一种特殊情况,就是这个黑莓4.6的浏览器,
在它下光判断一下这个element可能不靠谱,
可能这个元素已经不在页面上了,
可这个居然还能找到,
这边有个详细的解释,
我们来看一下,
可以看到这里有一个解释和例子,
我们先看一下这个解释是什么意思?
这里就是说可能在克隆节点的时候有问题,
其它情况好像没有这个问题。
这时候我们点击这个网址来看一下,
这里会弹出来一个DIV,
Fround是空,
就说明DIV没有找到,
我们通过控制台看到这里确实没有div,
这是正确的,
但是大家如果把这个拿到黑莓4.6下,
这时确实是会找到的。
(大家有这个条件的话,可以去测试一下)
我们查看一下源代码,
这里也很简单就是克隆,删除节点的过程,
但是在黑莓4.6下,
页面上是没有的,
但它却可以找到。
if ( elem && elem.parentNode ) {
// Inject the element directly into the jQuery object
this.length = 1;
this[0] = elem;
}
这里就是做了一个简单的处理,
当elem有没有的时候,
并且看它有没有父级,
大家可以想一下,
如果一个元素可以在页面上显示,
它必然有父级,不管任何一个元素,它都有父级,
但是一个元素不存在,它这个父级就会找不到,
所以说这时用双重判断会更加保险一些,
这是一个小问题,我们了解一下就好了。
接下来,我们看到这个 this.length 给它赋了个1,
因为在咱们前面说过,
在jQuery选择元素的时候,
它是存成了一个json的形式,
并不是一个数组,
这样的话这个长度是没有的,
所以说必须手动地给它添加个.length,
让它变成1,
这个JSON第0项,存的就是
这个第0的属性对应的就是这个元素,
接下来我们继续来看,
this.context = document;
this.selector = selector;
return this;
}
下边可以看到这个作用上下文,
肯定就是document,
接下来存的就是这个选择到的元素,
比如说这个元素叫#div1,
传到这个属性上,
这些都比较简单,
其实后面这个属性用到并不多,
到时候看到了再说,
然后直接 return this,
就返回这个对象,
就不需要再向后去查找了,
其实已经找到了,
就不用再往后找,
那咱们id这一块就帮大家分析了一下。
我们接着继续,
// HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
return ( context || rootjQuery ).find( selector );
我们走的就是else ... if,
可以发现上面写了:处理什么样的呢?
处理的就是 $(expr, $(...))?
我们先来看一看else ..if的判断,
else if ( !context || context.jquery ) {
判断了context执行上下文,
当这个执行上下文不在的时候,
肯定是走return的,
因为后面这个或就不用看了,
不存在走的是rootjQuery ,
这个变量就是我们的匹配页,
其实这个变量就是如下:
rootjQuery :$('document');
接着find的是谁呢?
find( selector );
find的就是我们选择到的元素,
这个字符串,find其实就是筛选的功能,
在一个指定的节点下去进行进一步的筛选,
// find到一些元素,
// 比如ul下的class为box的li标签
$(document).find('ul li.class');
其实像这种选择到了之后,
就是一种复杂的包括标签啊class或者是组合形式的,
都是通过find来实现的,
find源码是怎么设计的呢?
// find要调的就是Sizzle
find —> sizzle
所以说更复杂的选择器就用Sizzle,
find会进一步处理,最终会调Sizzle,
这一块就是选择到的元素,
自动地添加一些length长度啊、JSON下标,
它都可以完成。
咱们继续看下面这个else,
// HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
return ( context || rootjQuery ).find( selector );
// HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
return ( context || rootjQuery ).find( selector );
可以看到当这个context 不存在的情况下,
就会走下边的这一句话,
但是当它存在上下文的时候,
它就会判断下后面的context.jquery,
这时就看看上下文是不是jQuery对象,
如果是jQuery对象,它就会走return后面的,
如果不是jQuery对象的话,
它就会走else里return后面的,
这边有点绕,我们来一点点分析,
// 比如说我们平时写的时候,是不是可以这样写
$('ul',document).find('li');
// 除了上面的写法还有一种
$('ul',$('document')).find('li');
这两种写法其实都是可以的,
那让我们来先看一下前面这种,
如果说是document原生的形式,
它的上下文是肯定找不到jQuery这个属性的,
因为这个属性是在jQuery对象下面的,
所以说它就会走else,
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return this.constructor( context ).find( selector );
}
这时候我们知道前面这个 this.constructor 属性,
对应的就是jQuery,
所以说上面的它会走else对应的就是
else : jQuery(document).find();
接着,我们来看下面这一种,
这一种如果有执行上下文的,
它就会走下面这句话:
context.jquery
这句就为真,
为真的话就会走下面这句话,
// 走if的时候
if : jQuery(document).find();
所以说最终else if 和else,
这两块跳的都是同一个代码,
就是上面的代码,同样的,
只不过它们是处理不同的情况,
这一块字符串,咱们就分析完了,
最终其实可以发现这里面很多操作,
并没有在这个if中完成,
要像进一步学习,就要对这些方法进行了解
OK,咱们这段暂时讲到这里!
回看上一集:
别走开,下集更精彩。
喜欢文章的小伙伴,
希望大家多多转发分享,
你的分享就是我的动力!
以上是关于[No.8 jQuery源码解析—逐段解析的主要内容,如果未能解决你的问题,请参考以下文章