小菜的jquery-2.1.1源码分析(一)

自己根据自己的理解去尝试分析下大名鼎鼎的jquery的源码,一来提高自己使用jqueryAPI的使用能力,最重要的是提高自己javascript的能力,加油!

下载的是官网的http://code.jquery.com/jquery-2.1.1.js,2.1.1版本。

(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 )

一.第一行先定义了一个匿名函数并且执行,这是很多库的标准用法,在一个匿名函数闭包中运行,例如jquery,匿名函数里面的变量不会与外界冲突,只在9182行调用

window.jQuery = window.$ = jQuery;将jQuery和$挂载到window下,从而使用jQuery和$符来调用匿名函数中的各种方法和属性。

二.接着进行判断    if ( typeof module === "object" && typeof module.exports === "object" )。根据我的理解,是在之前如果应用到了符合CommonJS规范的js库,例如

Node.js,做一些冲突的协调,这个需要node.js等的一些知识。这个先不去理他。

三.如果没引用那些库,直接调用factory( global );factory和global正是这个大的匿名函数(function( global, factory )的两个参数,看一下这个匿名函数传的实参

(1)第一个参数window,首先判断  typeof window !== "undefined" ? window : this,如果window的类型不等于undefined,则传window参数,等于undefined,则传this,为什么

这么用,因为window是可以改变的,到后面可能会用到

(2)第二个参数是一个匿名函数function(window,noGlobal)。考虑到一般情况,function( global, factory ) {factiory(global)}(window,function...);这样这个匿名函数就容易理解了,        其实就是调用定义并且调用function(window,noGlobal),或者是 function(this,noGlobal)。之所以要这么用,因为这样会使作用域链变短,并且防止与其他库的冲突。

四.旧版的jquery好像没有上面的这个功能,是直接调用的function(window,noGlobal),下面开始漫长之路了,开始分析jquery的主函数 function(window,noGlobal)。

var arr = [];

var slice = arr.slice;

var concat = arr.concat;

var push = arr.push;

var indexOf = arr.indexOf;

var class2type = {};

var toString = class2type.toString;

var hasOwn = class2type.hasOwnProperty;

var support = {};

var
    // Use the correct document accordingly with window argument (sandbox)
    document = window.document,

    version = "2.1.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 );
    },

    // Support: Android<4.1
    // Make sure we trim BOM and NBSP
    rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,

    // Matches dashed string for camelizing
    rmsPrefix = /^-ms-/,
    rdashAlpha = /-([\da-z])/gi,

    // Used by jQuery.camelCase as callback to replace()
    fcamelCase = function( all, letter ) {
        return letter.toUpperCase();
    };

39~72行,定义了一些变量,在后面会用到,用到了再说

73~77行,

1 jQuery = function( selector, context ) {
2         // The jQuery object is actually just the init constructor ‘enhanced‘
3         // Need init if jQuery is called (just allow error to be thrown if not included)
4         return new jQuery.fn.init( selector, context );
5     }

定义了最重要的jQuery符号,例如我们调用$("a")即jQuery("a")相当于创建了jquery的一个实例,可以调用该实例的方法和属性,即new jQuery.fn.init("a");

78~86行,定义了一些正则表达式规则,在以后会用到。

rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g  表示不同序列编码的空格开始或结尾

rmsPrefix = /^-ms-/,以-ms-开头

rdashAlpha = /-([\da-z])/gi  以-后跟数字字母的前缀并且不区分大小写,这是为了将那些用-连接的字符串弄成驼峰的形式。

88~90行

fcamelCase = function( all, letter ) {
return letter.toUpperCase();
};

定义了一个简单的方法,就是返回参数的大写形式。

五.jQuery的原型

 1 jQuery.fn = jQuery.prototype = {
 2     // The current version of jQuery being used
 3     jquery: version,
 4
 5     constructor: jQuery,
 6
 7     // Start with an empty selector
 8     selector: "",
 9
10     // The default length of a jQuery object is 0
11     length: 0,
12
13     toArray: function() {
14         return slice.call( this );
15     },
16
17     // Get the Nth element in the matched element set OR
18     // Get the whole matched element set as a clean array
19     get: function( num ) {
20         return num != null ?
21
22             // Return just the one element from the set
23             ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
24
25             // Return all the elements in a clean array
26             slice.call( this );
27     },
28
29     // Take an array of elements and push it onto the stack
30     // (returning the new matched element set)
31     pushStack: function( elems ) {
32
33         // Build a new jQuery matched element set
34         var ret = jQuery.merge( this.constructor(), elems );
35
36         // Add the old object onto the stack (as a reference)
37         ret.prevObject = this;
38         ret.context = this.context;
39
40         // Return the newly-formed element set
41         return ret;
42     },
43
44     // Execute a callback for every element in the matched set.
45     // (You can seed the arguments with an array of args, but this is
46     // only used internally.)
47     each: function( callback, args ) {
48         return jQuery.each( this, callback, args );
49     },
50
51     map: function( callback ) {
52         return this.pushStack( jQuery.map(this, function( elem, i ) {
53             return callback.call( elem, i, elem );
54         }));
55     },
56
57     slice: function() {
58         return this.pushStack( slice.apply( this, arguments ) );
59     },
60
61     first: function() {
62         return this.eq( 0 );
63     },
64
65     last: function() {
66         return this.eq( -1 );
67     },
68
69     eq: function( i ) {
70         var len = this.length,
71             j = +i + ( i < 0 ? len : 0 );
72         return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
73     },
74
75     end: function() {
76         return this.prevObject || this.constructor(null);
77     },
78
79     // For internal use only.
80     // Behaves like an Array‘s method, not like a jQuery method.
81     push: push,
82     sort: arr.sort,
83     splice: arr.splice
84 };

这一片就是原型的属性和方法。jQuery.fn = jQuery.prototype是为了以后写的方便

比如直接可以用$.jquery就是调用jQuery.jquery,返回的是version,即在之前定义的常量,juqery的版本号。

93~103,定义了几个属性,比如version版本号,constructor构造器,selector选择器,length长度,因为等于说是初始化,都是空或者0。

104~168,接下来是原型上的方法,挨个分析下,并且举出一些例子。

后来发现jquery重写了slice方法,因此先来看slice方法

slice: function() {
return this.pushStack( slice.apply( this, arguments ) );
}

比较坑,又用到了pushStack方法,再来看

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,用到了merge方法,继续找,在424行找到,先看下

merge: function( first, second ) {
        var len = +second.length,
            j = 0,
            i = first.length;

        for ( ; j < len; j++ ) {
            first[ i++ ] = second[ j ];
        }

        first.length = i;

        return first;
    }

函数比较好看懂,该方法传两个参数,参数应该都为数组,len为第二个数组长度,i为第一个数组的长度,从[0,len)开始循环,达到的效果是两个数组进行合并到第一个参数数组,然后

再把第一个参数的长度设置成两个数组长度的和。返回第一个数组。

例如$.merge( [0,1,2], [2,3,4] )得到[0, 1, 2, 2, 3, 4]

往前捋,看pushStack方法

toArray: function() {
        return slice.call( this );
    },

就是类似于将字符串的slice方法应用,只不过是改了个名字罢了,一个是jquery对象上的方法,一个是字符串的方法而已。比如$("a").toArray(),就是将所有的匹配到的a标签组成的

jquery对象集合转化为数组

get: function( num ) {
        return num != null ?

            // Return just the one element from the set
            ( num < 0 ? this[ num + this.length ] : this[ num ] ) :

            // Return all the elements in a clean array
            slice.call( this );
    },

get方法,先判断参数num是否为null,如果是null,直接调用jquery的slice方法,即与toArray方法相同,如果不为null,再进行判断是否小于零,小于零,则从匹配到的jquery对象集合中返回

倒数第-num个对象,如果大于等于零,则返回对象集合中第num+1个jquery对象。

例如$("a").get(null)相当于调用$("a").toArray(),返回数组形式的jquery对象集合;

  $("a").get(1)返回jquery对象集合中第二个匹配到的jquery对象

  $("a").get(-1)返回jquery对象集合中倒数第一个匹配到的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;
    }

pushStack方法这个里面调用了jQuery对象的merge方法,比较蛋疼,等看到了merge方法再补充。

时间: 2024-10-16 16:38:52

小菜的jquery-2.1.1源码分析(一)的相关文章

转载Aaron ---- jQuery 2.0.3 源码分析core - 选择器

jQuery 2.0.3 源码分析core - 选择器(02) 声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 打开jQuery源码,一眼看去到处都充斥着正则表达式,jQuery框架的基础就是查询了,查询文档元素对象,所以狭隘的说呢,jQuery就是一个选择器,并这个基础上构建和运行查询过滤器! 工欲善其事,必先利其器,所以先从正则入手 我们来分解一个表达式 // A simple way to check for HTML strings // Prioritize

jQuery.lazyload使用及源码分析

前言: 貌似以前自己也写过图片懒加载插件,但是新公司使用的是jQuery.lazyload插件,为了更好的运用,自己还是把源码看了遍,分别记录了如何使用, 插件原理,各个配置属性的完整解释,demo实例,源码分析(较简短),源码分析可以配合使用,配置属性,原理进行阅读,如需转载,请注明出处 博客园 华子yjh 一.如何使用 // 最简单的使用,不带参数 $('img').lazyload(); // 带参数(配置对象),下面配置对象中的各个属性值都是默认的 $('img').lazyload({

转载Aaron博客 ---- jQuery 2.0.3 源码分析core - 整体架构

jQuery 2.0.3 源码分析core - 整体架构 整体架构 拜读一个开源框架,最想学到的就是设计的思想和实现的技巧. 废话不多说,jquery这么多年了分析都写烂了,老早以前就拜读过, 不过这几年都是做移动端,一直御用zepto, 最近抽出点时间把jquery又给扫一遍 我也不会照本宣科的翻译源码,结合自己的实际经验一起拜读吧! github上最新是jquery-master,加入了AMD规范了,我就以官方最新2.0.3为准 整体架构 jQuery框架的核心就是从HTML文档中匹配元素并

jQuery 2.0.3 源码分析 事件绑定 - bind/live/delegate/on

转:http://www.cnblogs.com/aaronjs/p/3440647.html?winzoom=1 事件(Event)是JavaScript应用跳动的心脏,通过使用JavaScript ,你可以监听特定事件的发生,并规定让某些事件发生以对这些事件做出响应 事件的基础就不重复讲解了,本来是定位源码分析实现的, 所以需要有一定的基础才行 为了下一步更好的理解内部的实现,所以首先得清楚的认识到事件接口的划分 网上资料遍地都是,但是作为一个jQuery系列的源码分析,我还是很有必要在重新

jQuery 2.0.3 源码分析 Deferrred概念

转载http://www.cnblogs.com/aaronjs/p/3348569.html JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而回调函数中则包含了后续的工作.这也 是造成异步编程困难的主要原因:我们一直习惯于“线性”地编写代码逻辑,但是大量异步操作所带来的回调函数,会把我们的算法分解地支离破碎.此时我们不能 用if来实现逻辑分支,也不能用while/for/do来实现循环,更不用提异步操作之间的组合.错误处理以及取消操作了.

jQuery.pushStack()原型方法源码分析

这次分析的方法跟前面不同,虽然pushStack也是原型方法之一,但是我们几乎从不用在页面调用,在参考手册里面也没有这个方法的使用说明,但是这个方法还是非常重要的,在使用很多jQuery的其他方式都会隐式的调用此方法: 它为以下方法提供支持:? ? jQuery 对象遍历:.eq()..first()..last()..slice()..map().? ? DOM 查找.过滤:.find()..not()..filter()..closest()..add()..andSelf().? ? DO

jQuery 2.0.3 源码分析 Deferred(最细的实现剖析,带图)

转载http://www.cnblogs.com/aaronjs/p/3356505.html Deferred的概念请看第一篇 http://www.cnblogs.com/aaronjs/p/3348569.html ******************构建Deferred对象时候的流程图************************** **********************源码解析********************** 因为callback被剥离出去后,整个deferred

jQuery 2.0.3 源码分析core - 选择器

转载http://www.cnblogs.com/aaronjs/p/3281911.html 声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 打开jQuery源码,一眼看去到处都充斥着正则表达式,jQuery框架的基础就是查询了,查询文档元素对象,所以狭隘的说呢,jQuery就是一个选择器,并这个基础上构建和运行查询过滤器! 工欲善其事,必先利其器,所以先从正则入手 我们来分解一个表达式 // A simple way to check for HTML strin

jQuery.extend()方法和jQuery.fn.extend()方法源码分析

这两个方法用的是相同的代码,一个用于给jQuery对象或者普通对象合并属性和方法一个是针对jQuery对象的实例,对于基本用法举几个例子: html代码如下: <!doctype html> <html> <head> <title></title> <script src='jquery-1.7.1.js'></script> </head> <body> <img src=''/>

最细的实现剖析:jQuery 2.0.3源码分析Deferred

Deferred的概念请看第一篇 http://www.cnblogs.com/aaronjs/p/3348569.html **构建Deferred对象时候的流程图** **源码解析** 因为callback被剥离出去后,整个deferred就显得非常的精简 jQuery.extend({ Deferred:function(){} when:function() )}对于extend的继承这个东东,在之前就提及过jquery如何处理内部jquery与init相互引用this的问题 对于JQ的