在core模块中,我们分析了实例化一个jQuery对象是由工厂方法jQuery交给了jQuery.fn.init。这个init实现是在init模块中完成的。

init模块最主要的任务还是实例化时传入的属性判断,具体实现还是交给另外的模块实现的。

比如:调用$(function(){})的时候,init判断是一个DOM ready函数,它就采用ready模块来实现。

再比如:调用$('<div></div>')的时候,因为判断字符串为一个html类型的,使用init模块会尝试去创建这个节点。这部分会依赖于parseHTML模块。

init模块比较简单,就不一步一步分析了,直接上分析的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
* 初始化一个jQuery对象
*/
define([
"../core",
"./var/rsingleTag",
"../traversing/findFilter"
], function( jQuery, rsingleTag ) {
// jQuery根对象(document)
var rootjQuery,
// 一个简便检查是否是html字符串的方法
// 优先处理 #id 的 <tag> 避免通过location.hash 进行 XSS 工具(#9521)
// 严格的html识别(#11290: 必须以<开头)
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
/**
* jQuery初始化方法
*
* jQuery初始化会做很多的事情
* 1.判断传入的selector是否满足选择结构
* 2.根据选择类型进行相关操作
* 3.context默认为document
* @param string selector 选择节点的相关属性或者需要创建节点的字符串
* @param string/$ context jQuery对象,或者选择节点的相关属性
* @return $ jQuery对象
*/
init = jQuery.fn.init = function( selector, context ) {
var match, elem;
// 当 $(""), $(null), $(undefined), $(false) 时不实例化
if ( !selector ) {
return this;
}
// 当selector 是是字符串时实例化
if ( typeof selector === "string" ) {
// 以<开头>结尾的 并且长度大于3 match 记录selector 例如:<div>
// 否则进行rquickExpr.exec( selector )方法
// rquickExpr.exec( selector ) 是一个正则表达式,主要是主要是匹配是否满足标签结构
if ( selector[0] === "<" && selector[ 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不为空 context为空或者match[1]不为空的情况
if ( match && (match[1] || !context) ) {
// 当match[1]不为空的情况jQuery会去构造一个节点
// 当$(html) 时
if ( match[1] ) {
context = context instanceof jQuery ? context[0] : context;
//把节点数组合并入jQuery对象
jQuery.merge( this, jQuery.parseHTML(
match[1],
context && context.nodeType ? context.ownerDocument || context : document,
true
) );
// 当 $(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;
// 当$(#id)时 那么采用getElementById查找节点
} else {
elem = document.getElementById( match[2] );
// 检测 parentNode 防止 Blackberry 4.6 回退
// 节点为空时context 为 document
if ( elem && elem.parentNode ) {
// 把elem并入jQuery对象
this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;
}
// 当 $(expr, $(...))时
} else if ( !context || context.jquery ) {
return ( context || rootjQuery ).find( selector );
// 当 $(expr, context)时
} else {
return this.constructor( context ).find( selector );
}
// 当 $(DOMElement)时
} else if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
// 当 $(function)时
// 主要为了简便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 );
};
// 为了实例使用,给init函数jQuery的原型
init.prototype = jQuery.fn;
// 初始化主要参考结点(document)
rootjQuery = jQuery( document );
return init;
});