jQuery 2.0.3 源码分析 回溯魔法 end()和pushStack()
了解了jQuery对DOM进行遍历背后的工作机制,可以在编写代码时有意识地避免一些不必要的重复操作,从而提升代码的性能
从这章开始慢慢插入jQuery内部一系列工具方法的实现
关于jQuery对象的包装
var $aaron = $("aaron");
通过对sizzle的分析呢,jQuery选择器,反正最终都是通过dom接口实现取值的, 但是通过jQuery处理后返回的不仅仅只有dom对象,而是一个包装容器
返回的jQuery对象:$aaron

jQuery对象,其中有个prevObject这个是干嘛用的呢?
jQuery对象栈
jQuery内部维护着一个jQuery对象栈。每个遍历方法都会找到一组新元素(一个jQuery对象),然后jQuery会把这组元素推入到栈中。
而每个jQuery对象都有三个属性:context、selector和prevObject,其中的prevObject属性就指向这个对象栈中的前一个对象,而通过这个属性可以回溯到最初的DOM元素集。
简单的测试demo
父元素ul,嵌套了li节点, 我们现给li绑定一个事件
<ul id="aaron">
parent
<li>child</li>
</ul>
这个很简单找到ul下面的li,绑定即可
var aaron = $("#aaron");
aaron.find('li').click(function(){
alert(1) //
})
此时我又想给父元素绑定一个事件,我们是不是又要在aaron上绑定事件?
通过find处理后,此时的上下文是每一个li了,所以必须要重新引用aaron父元素
aaron.click(function(){
alert(2) //
})
所有jQuery引入一个机制,可以回溯到之前的dom元素集合
通过end()方法
aaron.find('li').click(function(){
alert(1)
}).end().click(function(){
alert(2)
})
jQuery为我们操作这个内部对象栈提供了两个非常有用的方法:
- .end()
- .andBack()
调用第一个方法只是简单地弹出一个对象(结果就是回到前一个jQuery对象)。第二个方法更有意思,调用它会在栈中回溯一个位置,然后把两个位置上的元素集组合起来,并把这个新的、组合之后的元素集推入栈的上方。
利用这个DOM元素栈可以减少重复的查询和遍历的操作,而减少重复操作也正是优化jQuery代码性能的关键所在。
.end() 方法
大多数 jQueryDOM遍历 方法来操作 jQuery 对象实例,并创建一个新的对象,匹配一个不同的 DOM 元素集合。当发生这种情况时,实际上是新的元素集合被压入到对象内部维护的栈中。每次过滤方法都会被压入栈中。当我们需要返回到前一个状态时,我们可以使用end() 进行出栈操作,来返回栈中的前一个状态。
假设页面上有几个短的列表
<ul class="first">
<li class="foo">list item 1</li>
<li>list item 2</li>
<li class="bar">list item 3</li>
</ul>
<ul class="second">
<li class="foo">list item 1</li>
<li>list item 2</li>
<li class="bar">list item 3</li>
</ul>
end() 方法主要用于 jQuery 的链式属性中。当没有使用链式用法时,我们通常只是调用变量名上的前一个对象,所以我们不需要操作栈。使用 end() 时,我们可以一次性调用所有需要的方法:
$('ul.first').find('.foo').css('background-color', 'red')
.end().find('.bar').css('background-color', 'green');
链式的原理就是要返回当前操作的上下文
错误的:
跟上面的demo一样,上下文被切换了,所以下面find(‘bar’)出错了
$('ul.first').find('.foo').css('background-color', 'red').find('.bar').css('background-color', 'green');
正确的:
首先在链式用法中只在第一个列表中查找样式为 foo 的项目,并将其背景色变成红色。然后 end()返回调用 find() 之前的状态。因此,第二次 find() 将只会查找 <ul class="first"> 中的 '.bar',而不是继续在<li class="foo"> 中进行查找,结果是将匹配到的元素的背景色变成绿色。上述代码的最终结果是,第一个列表中的第 1 和第 3 个列表项的背景色有颜色,而第二个列表中的任何项目都没有背景色。
$('ul.first').find('.foo').css('background-color', 'red')
.end().find('.bar').css('background-color', 'green');
总的来说end方法就是回溯到上一个dom合集,因此对于链式操作与优化,这个方法还是很有意义的
源码实现
既然是回溯到上一个dom合集,那么肯定end方法中返回的就是一个jQuery对象了,所以我们看源码
其实就是返回prevObject对象了
end: function() {
return this.prevObject || this.constructor(null);
},
prevObject在什么情况下会产生?
在构建jQuery对象的时候,通过pushStack方法构建
jQuery.fn.extend({
find: function( selector ) {
...........................省略................................
//通过sizzle选择器,返回结果集
jQuery.find( selector, self[ i ], ret );
// Needed because $( selector, context ) becomes $( context ).find( selector )
ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
ret.selector = this.selector ? this.selector + " " + selector : selector;
return ret;
}
pushStack:将一个DOM元素集合加入到jQuery栈。
pushStack: function( elems ) {
// Build a new jQuery matched element set
var ret = jQuery.merge( this.constructor(), elems );
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
ret.context = this.context;
// Return the newly-formed element set
return ret;
},
流程解析:
1. 构建一个新的jQuery对象,无参 this.constructor(),只是返回引用this
2. jQuery.merge 把elems节点,合并到新的jQuery对象
3. 给返回的新jQuery对象添加属性prevObject ,所以我们看到prevObject 其实还是当前jQuery的一个引用罢了
所以也就是为什么通过prevObject能取到上一个合集的引用了
总结:
- pushStack()方法在jQuery的DOM操作中被频繁的使用, 如在parent(), find(), filter()中, 当然还有其他许多类似的方法, 它们往往需要返回一个jQuery封装过的DOM结果集.但在我们自己写jQuery代码的时候,却很少关注或使用过pushStack()
- 在jQuery内部,pushStack()方法通过改变一个jQuery对象的prevObject属性来"跟踪"链式调用中前一个方法返回的DOM结果集(被jQuery封装过,也是个jQuery对象,说是"跟踪",是因为实际存储的是个引用). 当我们再链式调用end()方法后, 内部就返回当前jQuery对象的prevObject.
jQuery 2.0.3 源码分析 回溯魔法 end()和pushStack()的更多相关文章
- jQuery 2.0.3 源码分析Sizzle引擎解析原理
jQuery 2.0.3 源码分析Sizzle引擎 - 解析原理 声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 先来回答博友的提问: 如何解析 div > p + ...
- jQuery 2.0.3 源码分析 Deferred(最细的实现剖析,带图)
Deferred的概念请看第一篇 http://www.cnblogs.com/aaronjs/p/3348569.html ******************构建Deferred对象时候的流程图* ...
- jQuery 2.0.3 源码分析core - 选择器
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 打开jQuery源码,一眼看去到处都充斥着正则表达式,jQuery框架的基础就是查询了,查询文档元素对象 ...
- jQuery 2.0.3 源码分析 Deferred概念
JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而回调函数中则包含了后续的工作.这也是造成异步编程困难的主要原因:我们一直习惯于“线性”地编写代码 ...
- jQuery 2.0.3 源码分析 事件绑定 - bind/live/delegate/on
事件(Event)是JavaScript应用跳动的心脏,通过使用JavaScript ,你可以监听特定事件的发生,并规定让某些事件发生以对这些事件做出响应 事件的基础就不重复讲解了,本来是定位源码分析 ...
- jQuery 2.0.3 源码分析 事件体系结构
那么jQuery事件处理机制能帮我们处理那些问题? 毋容置疑首先要解决浏览器事件兼容问题 可以在一个事件类型上添加多个事件处理函数,可以一次添加多个事件类型的事件处理函数 提供了常用事件的便捷方法 支 ...
- jQuery 2.0.3 源码分析 Deferrred概念
转载http://www.cnblogs.com/aaronjs/p/3348569.html JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而 ...
- jQuery 2.0.3 源码分析core - 整体架构
拜读一个开源框架,最想学到的就是设计的思想和实现的技巧. 废话不多说,jquery这么多年了分析都写烂了,老早以前就拜读过, 不过这几年都是做移动端,一直御用zepto, 最近抽出点时间把jquery ...
- jQuery 2.0.3 源码分析Sizzle引擎 - 词法解析
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 浏览器从下载文档到显示页面的过程是个复杂的过程,这里包含了重绘和重排.各家浏览器引擎的工作原理略有差别,但也有一定规则. 简 ...
随机推荐
- 【原】iOS学习之Quartz2D(1)
什么是Quartz2D 1.Quartz 2D 是一个二维绘图引擎,同时支持iOS和Mac系统 2.Quartz 2D 能完成的工作: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成 ...
- js闭包
先从闭包特点解释,应该更好理解. 闭包的两个特点: 1.作为一个函数变量的一个引用 - 当函数返回时,其处于激活状态.2.一个闭包就是当一个函数返回时,一个没有释放资源的栈区. 其实上面两点可以合成一 ...
- 【BZOJ3943】[Usaco2015 Feb]SuperBull 最小生成树
[BZOJ3943][Usaco2015 Feb]SuperBull Description Bessie and her friends are playing hoofball in the an ...
- 洛谷 P1827 美国血统 American Heritage Label:字符串Water
题目描述 农夫约翰非常认真地对待他的奶牛们的血统.然而他不是一个真正优秀的记帐员.他把他的奶牛 们的家谱作成二叉树,并且把二叉树以更线性的“树的中序遍历”和“树的前序遍历”的符号加以记录而 不是用图形 ...
- haha3
YOU - fhasd - fdks jf > jd sfkjd sf </div><div><span >print "helloworld&qu ...
- 分布式系统:怎么简单地解释Paxos算法?从二段提交、三段提交讲到Paxos
原文:https://www.quora.com/Distributed-Systems/What-is-a-simple-explanation-of-the-Paxos-algorithm 作者: ...
- 【转贴】Python处理海量数据的实战研究
最近看了July的一些关于Java处理海量数据的问题研究,深有感触,链接:http://blog.csdn.net/v_july_v/article/details/6685962 感谢July ^_ ...
- MongooseHelper
/** * Created by lbc on 2016/11/16. */var mongoose=require("mongoose");var db=mongoose.con ...
- STM32之ADC+步骤小技巧(英文)
神通广大的各位互联网的网友们.大家早上中午晚上好好好.今早起来很准时的收到了两条10086的扣月租的信息.心痛不已.怀着这心情.又开始了STM32的研究.早上做了计算机控制的PID实验,又让我想起了飞 ...
- ZK 样式使用
控件: <textbox id="usernameTb" sclass="login-user-input" placeholder="账号&q ...