jQuery是web程序员的必备js库,估计90%以上的web项目都会用到它。今天周末,心血来潮,打算仔细瞧瞧其庐山真面目。记得以前也对其分析过一次,半途而废了,也没有记录下来。呵呵。废话少说,直接开始。高手请绕行,勿喷,有错误请指正。谢谢。
用eclipse打开jquery-1.11.1.js,源代码如下所示:
- (function( global, factory ) {
- if ( typeof module === "object" && typeof module.exports === "object" ) {
- // For CommonJS and CommonJS-like environments where a proper window is present,
- // execute the factory and get jQuery
- // For environments that do not inherently posses a window with a document
- // (such as Node.js), expose a jQuery-making factory as module.exports
- // This accentuates the need for the creation of a real window
- // e.g. var jQuery = require("jquery")(window);
- // See ticket #14549 for more info
- module.exports = global.document ?
- factory( global, true ) :
- function( w ) {
- if ( !w.document ) {
- throw new Error( "jQuery requires a window with a document" );
- }
- return factory( w );
- };
- } else {
- factory( global );
- }
- // Pass this if window is not defined yet
- }(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
- // Can't do this because several apps including ASP.NET trace
- // the stack via arguments.caller.callee and Firefox dies if
- // you try to trace through "use strict" call chains. (#13335)
- // Support: Firefox 18+
- //
- var deletedIds = [];
- var slice = deletedIds.slice;
- ... ...
1. 在代码行的第一行的第一个左括号(的右边双击,定位到了代码的最后:
- ... ...
- // Expose jQuery and $ identifiers, even in
- // AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
- // and CommonJS for browser emulators (#13566)
- if ( typeof noGlobal === strundefined ) {
- window.jQuery = window.$ = jQuery;
- }
- return jQuery;
- }));
所以整个jquery源代码可以简化为:( ... ... );
就是一个小括号包含了一些javascript的表达式在里面。
2.我们再看看小括号里面是什么东西:
- (function( global, factory ) {
在第一行的第一个大括号{右边双击,通过代码定位知道了,这是一个匿名函数调用,可以简化为如下所示:
- (function( global, factory ) {
- ... ...
- }());
3.下面是最重要的:那么上面那个匿名函数的参数是什么呢?其参数的源代码如下:
- // Pass this if window is not defined yet
- }(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
很显然,第一个参数很简单:
- typeof window !== "undefined" ? window : this
就是全局对象window.
那么第二个参数呢?我们看到了function( window, noGlobal ) {,通过在大括号的右边双击,定位又到了代码的最后。所以第二个参数可以简化成如下所示:
- function( window, noGlobal ) {
- ... ...
- if ( typeof noGlobal === strundefined ) {
- window.jQuery = window.$ = jQuery;
- }
- return jQuery;
- }
所以第二个参数是一个函数,注意这里和上面的匿名函数调用不一样,这里没有调用,就是一个函数的定义,所以第二个参数就是一个函数,或者说函数句柄,也就是我们时时刻刻使用的jQuery,或者$,因为window.jQuery = window.$ = jQuery;。所以jQuery和$是等价的。
到了这里,那么整个代码就可以简化成如下:
- (function( global, factory ) {
- ... ...
- }(window, jQuery));
这里window传给形参global,jQuery传给形参factory。
4. 我们把上面我们刚刚得到的简化结果在细化一下,通过阅读代码注释,知道
- if ( typeof module === "object" && typeof module.exports === "object" )
上面这个判断是为了适应CommonJS的环境。如果没有CommonJS环境,那么代码就是下面这个样子:
- (function( global, factory ) {
- factory( global );
- }(window, jQuery));
显然其实就等价于:jQuery(window);
上面的分析,只是理解了jquery中外边的一些枝节。最重要的是理解函数jQuery(window)的定义。
5. 上面我们说到了函数function( window, noGlobal ){... ...}就是jQuery的函数定义。
那么:jQuery(window);调用其实就是:jQuery(window, undefined);
也就是: function(window, undefined)();调用。
也就是说noGlobal 参数为的值为undefined.我们Ctrl+F在源代码中查找noGlobal 的有关情况:
- function( window, noGlobal ){
- // General-purpose constants
- strundefined = typeof undefined,
- ... ...
- if ( typeof noGlobal === strundefined ) {
- window.jQuery = window.$ = jQuery;
- }
- return jQuery;
- }
所以函数function( window, noGlobal )的第二个参数用了noGlobal的含义是,是否将jQuery和$等价,并且赋值给全局对象window。[color=darkred]也就是决定了是否向全局变量中引入jQuery和$这两个全局变量[/color]。
所以如果在CommonJS环境中的话,并没有引入全局变量jQuery和$,而是仅仅将jQuery赋值给了module.exports:
- module.exports = global.document ? factory( global, true ) :function( w ) {};
也就是:module.exports = jQuery; 注意这里没有 $ 等价于 jQuery 了。
到了这里,jQuery源代码的外围枝节相关的代码已经分析完成。下面才是最核心的代码。
6. 下面开始看function( window, noGlobal ){... ...}的源代码:
- function( window, noGlobal ) {
- var deletedIds = [];
- var slice = deletedIds.slice;
- var concat = deletedIds.concat;
- var push = deletedIds.push;
- var indexOf = deletedIds.indexOf;
- var class2type = {};
- var toString = class2type.toString;
- var hasOwn = class2type.hasOwnProperty;
- var support = {};
- var
- version = "1.11.1",
- // 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 );
- },
- ... ...
最上面的几行代码应该是为将javascript中数组和对象的一些原生函数句柄赋值给jQuery 做准备的。
上面的代码明显:jQuery = new jQuery.fn.init( selector, context );
所以关键是jQuery.fn.init( selector, context );的定义。
在源代码中搜索:init 得到下面的代码:
- init = jQuery.fn.init = function( selector, context ) {
- var match, elem;
- // HANDLE: $(""), $(null), $(undefined), $(false)
- if ( !selector ) {
- return this;
- }
- // Handle HTML strings
- if ( typeof selector === "string" ) {
- if ( selector.charAt(0) === "<" && selector.charAt( 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) ) {
- // HANDLE: $(html) -> $(array)
- if ( match[1] ) {
- context = context instanceof jQuery ? context[0] : context;
- // scripts is true for back-compat
- // Intentionally let the error be thrown if parseHTML is not present
- 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;
- // HANDLE: $(#id)
- } else {
- elem = document.getElementById( match[2] );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- if ( elem && elem.parentNode ) {
- // Handle the case where IE and Opera return items
- // by name instead of ID
- if ( elem.id !== match[2] ) {
- return rootjQuery.find( selector );
- }
- // Otherwise, we inject the element directly into the jQuery object
- this.length = 1;
- this[0] = elem;
- }
- this.context = document;
- this.selector = selector;
- return this;
- }
- // HANDLE: $(expr, $(...))
- } else if ( !context || context.jquery ) {
- return ( context || rootjQuery ).find( selector );
- // HANDLE: $(expr, context)
- // (which is just equivalent to: $(context).find(expr)
- } else {
- return this.constructor( context ).find( selector );
- }
- // HANDLE: $(DOMElement)
- } else if ( selector.nodeType ) {
- this.context = this[0] = selector;
- this.length = 1;
- return this;
- // HANDLE: $(function)
- // Shortcut for document ready
- } else if ( jQuery.isFunction( selector ) ) {
- return typeof rootjQuery.ready !== "undefined" ?
- rootjQuery.ready( selector ) :
- // Execute immediately if ready is not present
- selector( jQuery );
- }
- if ( selector.selector !== undefined ) {
- this.selector = selector.selector;
- this.context = selector.context;
- }
- return jQuery.makeArray( selector, this );
- };
所以:jQuery = function( selector, context ) { ... ...};
也就是jQuery函数就是根据:选择子selector在对应的上下文context中进行查找,找到之后将其构造成一个jQuery对象返回,这样可以就可以使用这个返回的jQuery对象所具有的各种函数了。其实大多数情况下,我们一般没有传递context改jQuery函数,那么默认context就是document了。最后一行代码:
return jQuery.makeArray( selector, this );
告诉我们,jquery是面向集合(数组)编程的,他返回的都是集合(数组)。
上面这103行代码才是jquery的核心。
对于上面核心代码的分析,下次在具体分析。
相关推荐
本文将对jQuery 1.11.1版本的源码进行解析,探讨其核心设计理念和实现机制。 首先,我们来看看`jquery-1.11.1.js`,这是未压缩的jQuery源码,适合学习和理解。jQuery的核心在于它的选择器引擎(Sizzle)、DOM操作、...
《jQuery验证插件详解——基于jquery-validation-1.11.1.zip的...从基本的使用到高级的定制,从源码解析到多语言支持,每个部分都有助于我们掌握这个强大的工具,从而在实际项目中创建出高效、人性化的表单验证系统。
本文将详细解析"jquery拖拽插件源码"的相关知识点,包括如何实现拖拽功能、涉及的核心jQuery方法以及相关文件的作用。 首先,让我们了解拖拽功能的基本原理。在Web开发中,实现拖放(Drag and Drop)效果通常涉及到...
这个项目基于jQuery 1.11.1版本,一个广泛使用的JavaScript库,提供了丰富的DOM操作、事件处理和动画效果,使得开发者能够更加高效地编写交互式的网页应用。 在jQuery WEB音乐播放器中,主要涉及以下知识点: 1. *...
6. **图片元数据**:Viewer.js 可以解析图片的EXIF数据,自动调整图片的方向,使得显示更加准确。 7. **多语言支持**:除了默认的英文,Viewer.js 还提供了多种语言包,方便不同地区的用户使用。 8. **灵活的配置*...
【jQuery聊天表情代码转换图片.zip】是一个用于网页聊天功能的资源包,主要依赖于jQuery库,特别是`jquery.1.11.1.min.js`这个版本。jQuery是JavaScript的一个库,它极大地简化了DOM操作、事件处理、动画设计以及...
在"猜猜你是谁"游戏中,jQuery-1.11.1.js是主要的脚本文件,用于处理页面上的交互和逻辑运算。例如,当用户在输入框中填写姓名并点击"开始测试"按钮时,jQuery会捕获这个事件,然后执行相应的函数,将姓名作为参数...
3. **jquery-1.11.1.min.js**:这是一个jQuery库的版本,jQuery是一个广泛使用的JavaScript库,简化了DOM操作、事件处理和Ajax交互。在这个项目中,jQuery可能被用来辅助编写更简洁、高效的JavaScript代码。 4. **...