jQuery 源码精粹1 -- 核心模块

引言

核心模块core.jsjquery.js第一个包含的模块,浏览jquery源码文件,可以发现大部分文件都把它作为依赖。作为jquery最重要的模块,它到底做了哪些事情呢?

core.js

片段一

core.js首先声明了一系列的依赖模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
define( [
"./var/arr",
"./var/document",
"./var/getProto",
"./var/slice",
"./var/concat",
"./var/push",
"./var/indexOf",
"./var/class2type",
"./var/toString",
"./var/hasOwn",
"./var/fnToString",
"./var/ObjectFunctionString",
"./var/support",
"./core/DOMEval"
], function( arr, document, getProto, slice, concat, push, indexOf,
class2type, toString, hasOwn, fnToString, ObjectFunctionString,
support, DOMEval ) {...} );

这些模块提供了对通用功能的支持,通常比较简短,比如var/document的内容为:

1
2
3
4
5
define( function() {
"use strict";

return window.document;
} );

define(["./var/document"])在编译时,会被替换成var document = window.document;

在jQuery每个源文件的开头,都会看到类似的define语句,以优雅的形式定义了所需的依赖模块。

片段二:

1
2
3
4
5
6
7
8
9
10
var
version = "3.1.0",

// 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 );
},

jQuery的API调用形式是$(selector).action(props), 从这段代码可以看出,$(selector)返回的jQuery object,实际上是一个jQuery.fn.init实例,通过阅读core/init.js文件,我们可以知道在初始化实例时,解析传入的selector参数,根据不同的selector形式,生成相应的jQuery object(具体逻辑在下一篇分析), jQuery object是一个类似数组的对象,代表了一组被选中的DOM节点的集合。

片段三

core.js下一个代码片段:

1
2
3
4
5
6
jQuery.fn = jQuery.prototype = {
each: function() {...},
map: function() {...},
first: function(){...},
...
}

通过jQuery原型,定义了一些列诸如each,map,first等通用方法,支持类似数组的操作,所有的jQuery object都可以调用这些方法。

jQuery.fn添加方法定义,是jQuery各个模块以及用户自定义plugin, 扩展jQuery对象的标准做法。

同时在src/init.js的末尾,有这段代码:

1
init.prototype = jQuery.fn;

于是jQuery object实际和jQuery.fn.init object实际是等价的,正如我们在片段二所提到的。

片段四

core.js末尾的代码片段:

1
2
3
4
5
6
7
8
jQuery.extend = jQuery.fn.extend = function() {...};
jQuery.extend({
error: function( ) {},
noop: function() {},
isFunction: function() {},
isArray: function() {},
...
});

jQuery.extend代码内部,会迭代变量传入参数的每个属性,并将其赋值到jQuery命名空间,如果将deep参数设为true,则会递归遍历传入参数的所有属性。

jQuery extend很像类方法,可以让用户直接在jQuery命名空间定义全局方法,并以$.function_name()的形式进行调用。