手写jQuery源码

  虽然jQuery的时代已经过去,但是jQuery漂亮的源码依然非常值得学习。
  jQuery源码中很多方法已经不适用,例如数组相关的:类数组转数组的$.makeArray,数组判断$.isArray…等等,这些ES6都给我们封装到了Array对象中,但这不代表我们不应该去了解源码,去探索造源码的思想;
  很长时间,我都对源码敬而远之,现在,我终于勇敢对它揭面。
  感觉,一个新大陆扑面而来。

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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
(function (root) {
var testExp= /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
rejectExp = /^<(\w+)\s*\/?>/,
rootjQuery;

var jQuery = function (selector,context) {
return new jQuery.prototype.init(selector,context,rootjQuery);
};


jQuery.fn = jQuery.prototype = {
length: 0,
init: function( selector,context,rootjQuery ){
var match,elem;

if(!selector){
return this;
}

if(typeof selector === "string"){
if(selector.charAt(0) === "<" && selector.charAt(selector.length -1) === ">" && selector.length >= 3){
match = [null,selector,null];
}else{
match = testExp.exec(selector);
}

if(match[1]){
jQuery.merge(this,jQuery.parseHTML(selector,context && context.nodeType ? context : document));
}else{
elem = document.getElementById(match[2]);
if(elem && elem.nodeType){
this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;
}
}else if(selector.nodeType){
this.context = this[0] = selector;
this.length = 1;
return this;
}else if(jQuery.isFunction(selector)) {
rootjQuery.ready(selector)
}

},
ready: function (fn) {
document.addEventListener("DOMContentLoaded",jQuery.ready);
if(jQuery.isReady){
fn.call(document,jQuery);
}else{
jQuery.readyList.push(fn);
}
}
};

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

jQuery.extend = jQuery.fn.extend = function () {
var target = arguments[0] || {},
length = arguments.length,
copyIsArray = false,
deep = false,
option,
clone,
copy,
src,
name,
i = 1;

if(typeof arguments[0] === "boolean"){
deep = target;
target = arguments[i];
i++;
}

if(typeof target !== "object"){
target = {};
}

if(length === i){
target = this;
i--;
}

for(;i<length;i++){
if((option = arguments[i]) !== null){
for(name in option){
src = target[name];
copy = option[name];
if(deep && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))){
if(copyIsArray){
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
}else{
clone = src && jQuery.isPlainObject(src) ? src : {};
}

target[name] = jQuery.extend(deep,clone,copy);

}else if(copy !== undefined){
target[name] = copy;
}
}
}
}

return target;

};

jQuery.extend({
isPlainObject: function (obj) {
return toString.call(obj) === "[object Object]";
},
isArray: function (obj) {
return toString.call(obj) === "[object Array]";
},
isFunction: function (seletor) {
return typeof seletor === "function";
},
markArray: function (arr) {
var result = [];
if(arr && arr.length){
return jQuery.merge(result,arr);
}
},
merge: function (arg1,arg2) {
var i = arg1.length,
l = arg2.length,
j = 0;

if(typeof l === "number"){
for(;j<l;){
arg1[i++] = arg2[j++];
}
}else{
while(arg2[j] !== undefined){
arg1[i++] = arg2[j++];
}
}

return arg1;
},
parseHTML: function (data,context) {
if(!data || typeof data !== "string"){
return null;
}

var parse = rejectExp.exec(data);
return [context.createElement(parse[1])];
},
each: function (object,callback,args) {
var length = object.length,
name,i = 0;

if(args){
if(length === undefined){
for(name in object){
callback.apply(object,args);
}
}else{
for(;i<length;){
callback.apply(object[i++],args);
}
}
}else{
if(length === undefined){
for(name in object){
callback.call(object,name,object[name]);
}
}else{
for(;i<length;i++){
callback.call(object[i],i,object[i]);
}
}
}


},
isReady: false,
readyList : [],
ready: function () {
jQuery.isReady = true;
jQuery.each(jQuery.readyList,function (key,value) {
this.call(document);
});

jQuery.readyList = [];
}
});

rootjQuery = jQuery(document);
root.$ = root.jQuery = jQuery;
})(this);