jQuery

The Write Less, Do More, JavaScript Library

https://github.com/jquery/jquery

Cube - Page - Concave - Zoom - Linear - None - Default
Sky - Beige - Simple - Serif - Night - Default

节选自

《jQuery 技术内幕》

深入解析jQuery架构设计与实现原理

作者:高云

审校邀请 http://nuysoft.com/book.html

版权保护,谢绝以任何形式转载、出版、集结。

总体架构

入口模块、底层模块、功能模块

设计理念

  • 写更少的代码,做更多的事
  • 提升 JavaScript 开发体验
  • 以用为本

源码评价

精致、优雅、风骚

核心特性

  • 兼容主流浏览器,支持 IE 6.0+, FF 3.6+, Safari 5.0+, Opera, Chrome
  • 独特的链式语法、短小清晰的多功能接口
  • 高效灵活的CSS选择器、以及对CSS选择器的扩展
  • 便捷的插件扩展机制和丰富的插件

源码结构


(function( window, undefined ) {
    // 构造jQuery对象
    var jQuery = (function() {
        var jQuery = function( selector, context ) {
                return new jQuery.fn.init( selector, context, rootjQuery );
            }
        return jQuery;
    })();
    // 工具函数 Utilities
    // 回调函数对象 Callbacks Object
    // 异步队列对象 Deferred Object
    // 浏览器测试 Support
    // 数据缓存 Data
    // 队列 Queue
    // 属性操作 Attributes
    // 事件处理 Events
    // 选择器 Sizzle
    // DOM遍历 Traversing
    // DOM操作 Manipulation
    // 样式操作 CSS
    // 异步请求 AJAX
    // 动画 Effects
    // 坐标 Offset 和 大小 Dimensions
    window.jQuery = window.$ = jQuery;
})(window);

		

入口模块、底层模块、功能模块

自调用匿名函数


(function( window, undefined ) {
    // jQuery的所有代码
})(window);
		
  1. 为什么要创建这样一个自调用匿名函数呢?
  2. 为什么要传入 window 对象呢?
  3. 为什么要在在参数列表中增加 undefined 呢?
  4. 注意到源码最后的分号了吗?

构造 jQuery 对象

jQuery.fn.init()

构造函数 jQuery()

总体结构


  16 (function( window, undefined ) {
         // 构造 jQuery 对象
  22     var jQuery = (function() {
  25         var jQuery = function( selector, context ) {
  27                 return new jQuery.fn.init( selector, context, rootjQuery );
  28             },
                 // 一堆局部变量声明
  97         jQuery.fn = jQuery.prototype = {
  98             constructor: jQuery,
  99             init: function( selector, context, rootjQuery ) { ... },
                 // 一堆原型属性和方法
 319         };
 322         jQuery.fn.init.prototype = jQuery.fn;
 324         jQuery.extend = jQuery.fn.extend = function() { ... };
 388         jQuery.extend({
                 // 一堆静态属性和方法
 892         });
 955         return jQuery;
 957     })();
          // 省略其他模块的代码 ...
9246     window.jQuery = window.$ = jQuery;
9266 })( window );
		

为什么

为什么要在调用构造函数 jQuery() 内部用运算符 new 创建并返回另一个构造函数的实例?

为什么

为什么在第97行执行 jQuery.fn = jQuery.prototype,设置 jQuery.fn 指向构造函数 jQuery() 的原型对象 jQuery.prototype?

为什么

既然调用构造函数 jQuery() 返回的 jQuery 对象实际上是构造函数 jQuery.fn.init() 的实例,为什么能在构造函数 jQuery.fn.init() 的实例上调用构造函数 jQuery() 的原型方法和属性,例如: $('#id').length 和 $('#id').size()?

为什么

为什么要把第25~955行的代码包裹在一个自调用匿名函数中,然后把第25行定义的构造函数 jQuery() 作为返回值赋值给为第22行的 jQuery 变量?去掉这个自调用匿名函数,直接在第25行定义构造函数 jQuery() 不也可以吗?去掉了不是更容易阅读和理解吗?

为什么

为什么要覆盖构造函数 jQuery() 的原型对象 jQuery.prototype?

jQuery.fn.init( selector, context, rootjQuery )

原型属性和方法


  97 jQuery.fn = jQuery.prototype = {
  98     constructor: jQuery,
  99     init: function( selector, context, rootjQuery ) {}
 210     selector: "",
 213     jquery: "1.7.1",
 216     length: 0,
 219     size: function() {},
 223     toArray: function() {},
 229     get: function( num ) {},
 241     pushStack: function( elems, name, selector ) {},
 270     each: function( callback, args ) {},
 274     ready: function( fn ) {}, //
 284     eq: function( i ) {},
 291     first: function() {},
 295     last: function() {},
 299     slice: function() {},
 304     map: function( callback ) {},
 310     end: function() {},
 316     push: push,
 317     sort: [].sort,
 318     splice: [].splice
 319 };
		

静态属性和方法


 388 jQuery.extend({
 389     noConflict: function( deep ) {},
 402     isReady: false,
 406     readyWait: 1,
 409     holdReady: function( hold ) {},
 418     ready: function( wait ) {},
 444     bindReady: function() {},
 492     isFunction: function( obj ) {},
 496     isArray: Array.isArray || function( obj ) {},
 501     isWindow: function( obj ) {},
 505     isNumeric: function( obj ) {},
 509     type: function( obj ) {},
 515     isPlainObject: function( obj ) {},
 544     isEmptyObject: function( obj ) {},
 551     error: function( msg ) {},
 555     parseJSON: function( data ) {},
 581     parseXML: function( data ) {},
 601     noop: function() {},
 606     globalEval: function( data ) {},
 619     camelCase: function( string ) {},
 623     nodeName: function( elem, name ) {},
 628     each: function( object, callback, args ) {},
 669     trim: trim ? function( text ) {} : function( text ) {},
 684     makeArray: function( array, results ) {},
 702     inArray: function( elem, array, i ) {},
 724     merge: function( first, second ) {},
 744     grep: function( elems, callback, inv ) {},
 761     map: function( elems, callback, arg ) {},
 794     guid: 1,
 798     proxy: function( fn, context ) {},
 825     access: function( elems, key, value, exec, fn, pass ) {},
 852     now: function() {},
 858     uaMatch: function( ua ) {},
 870     sub: function() {},
 891     browser: {}
 892 });
		

总结

  • 构造函数的 7 种用法
  • 源码总体结构
  • 5 个为什么
  • 构造函数 jQuery.fn.init() 的 12 个分支
  • 原型属性和方法
  • 静态属性和方法

异步请求 AJAX

动画 Effects

THE END

BY @nuysoft 高云 一淘-UX-墨智

mozhi.gyy@taobao.com nuysoft@gmail.com

http://nuysoft.com/

http://nuysoft.iteye.com/ http://cnblogs.com/nuysoft