源代码阅读方法 jQuery源码解析 核心模块core.js

之前想看看jQuery的源代码但并没有看下去,可能是因为没有掌握好方法,现在尝试按照以下的方法进行阅读,而阅读的前提就是:这里假设你已经学会了jQuery的基本使用,对Javascript也比较熟悉,也大致浏览了它的API,已经把jQuery的源代码从github获取到了,并查看了一番(https://github.com/jquery/jquery)。

阅读源代码的步骤:详细阅读API和官方给定的文档;找到一个感兴趣的API;从最核心的基础函数库开始阅读,可以先大致了解,理清各层的关系;顺着调用的思路详细阅读,跟踪到每一条注释和变量;同样的方法阅读其他的API。

现在我们开始顺着阅读源代码的思路,找到一个感兴趣而比较简单的API开始阅读,这里就在API文档中找到核心部分的 core.js。

1、首先是分析源代码的基本框架

jQuery中最基本的一个文件就是core.js,打开这个文件大致浏览下:

1.1、项目的编译顺序

首先我们可以看到jQuery项目中的 Gruntfile.js 文件,里面就涉及到了src目录下各个模块文件的编译顺序:

build: {
“dist/jquery.js”: [
“src/intro.js”,
“src/core.js”,
“src/callbacks.js”,
“src/deferred.js”,
“src/support.js”,
“src/data.js”,
“src/queue.js”,
“src/attributes.js”,
“src/event.js”,
“src/selector.js”,
“src/traversing.js”,
“src/manipulation.js”,

    { flag: "css", src: "src/css.js" },
    "src/serialize.js",
    { flag: "ajax", src: "src/ajax.js" },
    { flag: "ajax/script", src: "src/ajax/script.js", needs: \["ajax"\]  },
    { flag: "ajax/jsonp", src: "src/ajax/jsonp.js", needs: \[ "ajax", "ajax/script" \]  },
    { flag: "ajax/xhr", src: "src/ajax/xhr.js", needs: \["ajax"\]  },
    { flag: "effects", src: "src/effects.js", needs: \["css"\] },
    { flag: "offset", src: "src/offset.js", needs: \["css"\] },
    { flag: "dimensions", src: "src/dimensions.js", needs: \["css"\] },
    { flag: "deprecated", src: "src/deprecated.js" },

    "src/exports.js",
    "src/outro.js"
\]

},

可以按照这个顺序阅读源代码。下面就从core.js中抽取出最关键的一些架构代码进行解释。

1.2、关键的架构代码

1.2.1、变量和正则表达式的声明部分

这里我们关注的一个是:

jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor ‘enhanced’
return new jQuery.fn.init( selector, context, rootjQuery );
},

在变量定义部分定义了jQuery,这里又调用了jQuery.fn.init来创建一个对象返回。

1.2.2、jQuery.fn = jQuery.prototype 对象

jQuery.fn = jQuery.prototype 把jQuery的原型prototype赋给jQuery.fn,所以jQuery.fn.init实际上就是jQuery.protype.init方法。

1.2.3、jQuery.fn.init.prototype = jQuery.fn

jQuery.fn.init.prototype = jQuery.fn;

这句话的意思就是让jQuery.fn.init继承jQuery.fn,使得jQuery.fn有的属性,jQuery.fn.init也有。

所以回到第1步中的jQuery函数:

jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor ‘enhanced’
return new jQuery.fn.init( selector, context, rootjQuery );
},

这里的jQuery函数实际上是执行了:

return new jQuery.fn.init(selector, context, rootjQuery);

所以其实返回的对象也就相当于有jQuery.fn对象的所有属性。

其实这种初始化jQuery的方法在很多JS代码中都是非常常见的。

由此可见,jQuery方法就是一个工厂方法,用来产生jQuery对象的实例。

1.2.4、jQuery.extend = jQuery.fn.extend对象

这样,所有的由 new jQuery 方法创建的对象都具有了extend方法。关于这个extend方法的作用,其实可以扩展jQuery对象实例的功能,这在插件开发中很有用,编写插件的方法参考这里:

jQuery插件实现的方法和原理简单说明

jQuery插件的编写相关技术 设计总结和最佳实践

1.2.5、jQuery.extend()对jQuery进行扩展

1.2.6、jQuery.ready.promise = function( obj ) 函数

1.2.7、function isArraylike( obj ) {} 函数

1.2.8、rootjQuery = jQuery(document);

这句话产生的实例只是在core.js内部使用。

1.2.9、window.jQuery = window.$ = jQuery;

最后在 exports.js 文件里面看到这个:

// Expose jQuery to the global object
window.jQuery = window.$ = jQuery;

就是将jQuery($)这个Function对象暴露到全局范围。

3、现在是时候开始仔细阅读里面的方法了

3.1、init方法

首先看到jQuery.fn = jQuery.prototype中的init方法:

根据上面的分析,这个方法是在jQuery函数(如下)被调用的,其实就是jQuery的选择器。

jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor ‘enhanced’
return new jQuery.fn.init( selector, context, rootjQuery );
},

jQuery([selector,[context]])
返回值:jQuery
概述
这个函数接收一个包含 CSS 选择器的字符串,然后用这个字符串去匹配一组元素。

仔细阅读可以发现,init方法中通过对各种类型的selector选择子做不同的处理,把获取或者根据条件创建的dom节点存到this数组中然后返回。

3.2、get([index])方法

下面看看get([index])的代码:

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

        // Return a 'clean' array
        this.toArray() :

        // Return just the object
        ( num < 0 ? this\[ this.length + num \] : this\[ num \] );
},

get([index])
返回值:Element

概述

取得其中一个匹配的元素。 num表示取得第几个匹配的元素。

这能够让你选择一个实际的DOM 元素并且对他直接操作,而不是通过 jQuery 函数。$(this).get(0)与$(this)[0]等价。

基本用法如下:

$(“img”).get(0);

这段代码在 jQuery.fn = jQuery.prototype 中。这里很容易可以看出,当传入的num为空时,就把this转换为空数组返回,当num不为空时,就按照num取到对应第几个元素。而这里的this就是jQuery.fn作用域,以this数组的形式存储了通过selector获取到的dom节点。

arthinking wechat
欢迎关注itzhai公众号