本书由阿里巴巴资深前端开发工程师撰写,从源代码角度全面而系统地解读了jQuery的17个模块的架构设计理念和内部实现原理,旨在帮助读者参透jQuery中的实现技巧和技术精髓,同时本书也对广大开发者如何通过阅读源代码来提升编码能力和软件架构能力提供了指导。
本书首先通过“总体架构”梳理了各个模块的分类、功能和依赖关系,让大家对jQuery的工作原理有大致的印象;进而通过“构造jQuery对象”章节分析了构造函数jQuery()的各种用法和内部构造过程;接着详细分析了底层支持模块的源码实现,包括:选择器Sizzle、异步队列Deferred、数据缓存Data、队列Queue、浏览器功能测试Support;最后详细分析了功能模块的源码实现,包括:属性操作Attributes、事件系统Events、DOM遍历Traversing、DOM操作Manipulation、样式操作CSS、异步请求Ajax、动画Effects。
本书在分析每个模块时均采用由浅入深的方式,先概述功能、用法、结构和实现原理,然后介绍关键步骤和分析源码实现。让读者不仅知其然,而且知其所以然。事实上,本书的根本价值在于传达一种通过阅读源码快速成长的方式。无论是前端新人,还是经验丰富的老手,只要是对JavaScript感兴趣的开发人员,都会从本书中受益。
前 言
jQuery是业界最流行的JavaScript库,其API非常精致和优雅,但是jQuery的源码却庞大且晦涩难懂,在本书开始写作时发布的1.7.1版本有9266行代码,涉及17个模块,读起来常常是一头雾水、有心无力。本书尝试对jQuery的源码进行系统、完整的介绍和分析,阐述jQuery的设计理念、实现原理和源码实现。
为什么要写这本书
笔者在2010年参与了一款卫星机顶盒用户界面的设计和开发,程序运行在机顶盒中间件供应商提供的一款定制浏览器上,在开发过程中,发现这款浏览器的行为类似于古老的IE 5,各种缺陷和bug折磨得笔者苦不堪言,所以希望引入jQuery作为基础库,并开发一些通用组件和接口来简化开发过程,可是很快又发现这款浏览器对正则表达式的支持非常粗糙,导致选择器引擎Sizzle根本无法运行。此时,对jQuery进行简单改造已经满足不了需求。
然而令人惊艳的是,这款浏览器提供了与操作系统、文件系统、中间件、播放器、智能卡和卫星接收器等交互的JavaScript API,例如,待机&关机、文件读写、计费、卫星锁频、数据接收等。鉴于这种复杂的体系架构,以及对浏览器缺陷的完善也非短期可以完成,笔者开始为这款机顶盒浏览器移植jQuery,从而开始了对jQuery源码的学习和分析。
从2011年6月开始,笔者开始把心得和记录整理成《jQuery 1.6.1源码分析系列》,陆续发表在程序员社区ITEye和博客园上,本书最初的内容也是基于这个系列而来的。《jQuery 1.6.1源码分析系列》成体系但尚粗糙不堪,因此本书基于jQuery 1.7.1几乎全部重写,在内容上更加完善和严谨。
希望本书对读者能有所帮助。
读者对象
本书适合初级、中级、高级前端开发工程师,以及对前端开发感兴趣的读者。
在阅读本书之前,读者应该初步掌握JavaScript、HTML、CSS的基础知识,初步掌握jQuery的使用,或者有其他语言基础。
如何阅读本书
本书共分为四大部分,首先介绍了jQuery的总体架构,然后分别分析了构造jQuery对象模块、底层支持模块和功能模块的源码实现。在阅读本书时,首先建议读者建立一个源码阅读和调试环境,在阅读过程中进行各种尝试和验证,加深对源码的理解;在阅读本书的每个章节前,建议读者先仔细阅读相应的官方文档,并验证官方示例,掌握API的功能和用法。
第一部分(第1章)对jQuery的设计理念、总体架构和源码结构进行了介绍和分析,让读者对jQuery有整体的认识。
第二部分(第2章)详细介绍和分析了构造函数jQuery()的用法、构造过程、原型属性和方法、静态属性和方法。
第三部分(第3~7章)详细分析了底层支持模块的源码实现,包括选择器Sizzle、异步队列Deferred Object、数据缓存Data、队列Queue、浏览器功能测试Support。
第四部分(第8~14章)详细分析了功能模块的源码实现,包括属性操作Attributes、事件系统Events、DOM遍历Traversing、DOM操作Manipulation、样式操作CSS、异步请求Ajax、动画Effects。
勘误和支持
由于笔者水平有限,再加上写作时的疏漏,书中难免存在许多需要改进之处。在此,欢迎读者朋友们指出书中存在的问题,并提出指导性意见,不胜感谢。提交地址为https://github.com/nuysoft/jquery-errata-support/issues,勘误内容将在http://nuysoft.com/jquery.html上发布。
致谢
首先要向jQuery作者John Resig、jQuery团队和jQuery社区致敬,是你们繁荣了JavaScript。
感谢机械工业出版社的杨绣国(Lisa)编辑,她对本书进行了大量润色,修订和批注的内容比我写的内容要多得多。本书的进度和内容在写作期间不断变更,因为她的不断激励和反复修订,才使本书得以呈现在广大读者面前。感谢朱秀英编辑,她修正了书稿中诸多不完善之处。感谢为本书拾遗补缺的诸多幕后编辑。
感谢为本书初稿给出反馈意见的所有人:古西风(叶克良)、左莫(徐波)、逸才(陈养剑)、崇志(李德强)、李志博、王阳光、符宝(徐丽丽)、余鹏、许杰。你们的宝贵意见使本书内容更加完善、更加准确。
本书最初的内容以及得到出版的机遇,源自发表在ITEye和博客园的一系列博客,感谢这两个社区,以及因此结识的朋友们。
高云(nuysoft)
第一部分 总体架构
第1章 总体架构 2
1.1 设计理念 2
1.2 总体架构 2
1.3 自调用匿名函数 4
1.4 总结 6
第二部分 构造jQuery对象
第2章 构造jQuery对象 8
2.1 构造函数jQuery() 8
2.1.1 jQuery( selector [, context] ) 9
2.1.2 jQuery( html [, ownerDocument] )、jQuery( html, props ) 9
2.1.3 jQuery( element )、jQuery( elementArray ) 10
2.1.4 jQuery( object ) 10
2.1.5 jQuery( callback ) 11
2.1.6 jQuery( jQuery object ) 11
2.1.7 jQuery() 11
2.2 总体结构 11
2.3 jQuery.fn.init( selector, context, rootjQuery ) 13
2.3.1 12个分支 13
2.3.2 源码分析 14
2.3.3 小结 21
2.4 jQuery.buildFragment( args, nodes, scripts ) 22
2.4.1 实现原理 22
2.4.2 源码分析 22
2.4.3 小结 26
2.5 jQuery.clean( elems, context, fragment, scripts ) 27
2.5.1 实现原理 27
2.5.2 源码分析 27
2.5.3 小结 39
2.6 jQuery.extend()、jQuery.fn.extend() 40
2.6.1 如何使用 40
2.6.2 源码分析 40
2.7 原型属性和方法 43
2.7.1 .selector、.jquery、.length、.size() 44
2.7.2 .toArray()、.get( [index] ) 45
2.7.3 .each( function(index, Element) )、jQuery.each( collection, callback (indexInArray, valueOfElement) ) 46
2.7.4 .map( callback(index, domElement) )、jQuery.map( arrayOrObject, callback(value, indexOrKey) ) 47
2.7.5 .pushStack( elements, name, arguments ) 49
2.7.6 .end() 51
2.7.7 .eq( index )、.first()、.last()、.slice( start [, end] ) 51
2.7.8 .push( value, ... )、.sort( [orderfunc] )、.splice( start,deleteCount, value, ... ) 52
2.7.9 小结 53
2.8 静态属性和方法 54
2.8.1 jQuery.noConflict( [removeAll] ) 55
2.8.2 类型检测:jQuery.isFunction( obj )、jQuery.isArray( obj )、jQuery.isWindow( obj )、jQuery.isNumeric( value )、jQuery.type( obj )、jQuery.isPlainObject( object )、jQuery.isEmptyObject( object ) 56
2.8.3 解析JSON和XML:jQuery.parseJSON( data )、jQuery.parseXML( data ) 60
2.8.4 jQuery.globalEval( code ) 65
2.8.5 jQuery.camelCase( string ) 65
2.8.6 jQuery.nodeName( elem, name ) 66
2.8.7 jQuery.trim( str ) 67
2.8.8 数组操作方法:jQuery.makeArray( obj )、jQuery.inArray( value, array [, fromIndex] )、jQuery.merge( first, second )、jQuery.grep( array, function(elementOfArray, indexInArray) [, invert] ) 68
2.8.9 jQuery.guid、jQuery.proxy( function, context ) 72
2.8.10 jQuery.access( elems, key, value, exec, fn( elem, key, value ), pass ) 74
2.8.11 jQuery.error( message )、jQuery.noop()、jQuery.now() 75
2.8.12 浏览器嗅探:jQuery.uaMatch( ua )、jQuery.browser 76
2.8.13 小结 77
2.9 总结 77
第三部分 底层支持模块
第3章 选择器Sizzle 80
3.1 总体结构 81
3.2 选择器表达式 83
3.3 设计思路 84
3.4 Sizzle( selector, context, results, seed ) 86
3.5 正则chunker 94
3.6 Sizzle.find( expr, context, isXML ) 94
3.7 Sizzle.filter( expr, set, inplace, not ) 99
3.8 Sizzle.selectors.relative 103
3.8.1 "+" 105
3.8.2 ">" 106
3.8.3 "" 108
3.8.4 "~" 108
3.8.5 dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) 109
3.8.6 dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) 111
3.9 Sizzle.selectors 112
3.9.1 Sizzle.selectors.order 112
3.9.2 Sizzle.selectors.match/leftMatch 113
3.9.3 Sizzle.selectors.find 122
3.9.4 Sizzle.selectors.preFilter 123
3.9.5 Sizzle.selectors.filters 129
3.9.6 Sizzle.selectors.setFilters 132
3.9.7 Sizzle.selectors.filter 133
3.10 工具方法 140
3.10.1 Sizzle.uniqueSort( results ) 140
3.10.2 sortOrder( a, b ) 141
3.10.3 Sizzle.contains( a, b ) 144
3.10.4 Sizzle.error( msg ) 145
3.10.5 Sizzle.getText( elem ) 145
3.11 便捷方法 146
3.11.1 Sizzle.matches( expr, set ) 146
3.11.2 Sizzle.matchesSelector( node, expr ) 146
3.12 jQuery扩展 147
3.12.1 暴露Sizzle给jQuery 147
3.12.2 .find( selector ) 148
3.12.3 .has( target ) 149
3.12.4 .not( selector )、.filter( selector ) 150
3.12.5 .is( selector ) 152
3.12.6 .closest( selectors, context ) 153
3.12.7 .index( elem ) 154
3.12.8 .add( selector, context ) 155
3.12.9 jQuery.filter( expr, elems, not ) 156
3.12.10 :animated 157
3.12.11 hidden、:visible 157
3.13 总结 158