jQuery源码研究的范本是3.3.1版本。
昨天看的是jQuery
源码中最顶部的模块规范判断部分,其主要作用是针对所处不同环境支持的模块规范给出兼容性操作。而jQuery
真正主体的部分是在工厂函数中的,在里面实现了所有功能,下面我将工厂函数的函数体按行标记分割成许多小的模块,分割的依据是按照功能块的不同,下面列出我分割好的jQuery简化框架:
1(function(global, factory){
2 "use strict";
3
4 //模块规范判断
5 if ( typeof module === "object" && typeof module.exports === "object" ) { //CommonJS类规范判断,由于nodejs支持CommonJS规范,所以判断此条件成立时,则执行下列语句来兼容nodejs
6 module.exports = global.document ? //三目运算符:先判断环境是否支持window.document属性
7 factory( global, true ) : //如支持,module.exports = factory( global, true ),把jQ工厂函数作为模块暴露到node.js里面。
8 function( w ) { //如不支持,就通过本行的匿名函数抛出错误,并返回jQ的工厂函数,但功能是否都支持,就鬼知道了...
9 if ( !w.document ) {
10 throw new Error( "jQuery requires a window with a document" );
11 }
12 return factory( w );
13 };
14 } else { //如果没有使用CommonJS规范的框架,就直接引入jQ工厂函数
15 factory( global );
16 }
17
18 //匿名函数传入两个参数:typeof window !== "undefined" ? window : this 和 jQ工厂函数(jq的完成功能在此)
19})(typeof window !== "undefined" ? window : this, function(window, noGlobal){
20
21 // line:(48 - 144) 定义一些变量和函数 jQuery = function(){}
22
23 // line: (146 - 225) 为jQ对象添加一些方法和属性
24
25 // line: (227 - 294) jQ的继承方法
26
27 // line: (296 - 471) jQuery.extend({}) 为jQ对象扩展一些工具方法
28
29 // line: (499 - 2752) Sizzle : 复杂选择器的实现
30
31 // line: (3225 - 3417) Callbacks : 回调对象 : 对函数的统一管理
32
33 // line: (3460 - 3806) Deferred : 延迟对象 : 对异步的统一管理
34
35 // line: (3976 - 4326) data() : 数据缓存
36
37 // line: (4329 - 4461) queue() : 队列方法 : 执行顺序的管理
38
39 // line: (4462 - 4669) show()、hide()、toggle()等方法的实现
40
41 // line: (4861 - 5588) on() 等事件相关的操作方法
42
43 // line: (5591 - 6058) DOM操作 : 添加 删除 获取 包装 DOM筛选
44
45 // line: (6062 - 6679) css() : 样式的操作
46
47 // line: (6682 - 7487) animate() : 运动的方法
48
49 // line: (6682 - 7487) animate() : 运动的方法
50
51 // line: (7490 - 7777) 表单元素的属性操作
52
53 // line: (7790 - 7962) addClass、removeClass 等样式类方法
54
55 // line: (7967 - 8143) val() 等方法
56
57 // line: (8151 - 8336) trigger() 方法
58
59 // line: (8388 - 8526) 表单转换 serialize() 方法
60
61 // line: (8529 - 9929) 提交的数据和ajax() : ajax() load() getJSON()
62
63 // line: (9943 - 10220) offset() : 位置和尺寸的方法
64
65 // line: (10225 - 10224) bind() : 绑定方法和解绑方法
66
67 // line: (10324 - 10328) AMD模块规范兼容
68
69 // line: (10333 - 10358) 返回jQuery
70})
在行48-144
中,定义了一些变量和jQuery
函数。用部分变量储存了数组和对象的一些方法,便于后续调用简化易懂,如var getProto = Object.getPrototypeOf
,就是简化获取对象属性的方法,还有var push = arr.push;
等。
还定义了一些方法,isFunction()
、isWindow()
:
1//返回布尔值,判断参数是否为函数
2var isFunction = function isFunction( obj ) {
3 return typeof obj === "function" && typeof obj.nodeType !== "number";
4};
解释:当参数obj
的typeof
值全等于function
且不为节点类型时,才返回true
,严谨的判断参数是否为一个函数。
应用:$.isFunction(fn)
1//判断是否为window对象,返回布尔值
2var isWindow = function(obj){
3 return obj != null && obj === obj.window;
4}
解释:window
对象是浏览器的全局变量,该对象有一个属性window
,通过window === window.window
可以判断参数全等于Window
对象。
应用:
1$.isWindow(window); //true
2$.isWindow(this); //true
3// 浏览器环境中,顶层作用域中时this指向window,在nodejs环境中顶层作用域中全局变量是global
1function toType( obj ) {
2 if ( obj == null ) {
3 return obj + ""; //返回 'null' 字符串
4 }
5
6 return typeof obj === "object" || typeof obj === "function" ?
7 class2type[ toString.call( obj ) ] || "object" :
8 typeof obj;
9}
解释:检测参数类型,如参数为null
,则返回字符串'null'
值;如参数类型为对象或函数,则统一返回object
类型;否则就返回其相应的类型,如参数为字符串就返回string
类型。
最后来看下jQuery函数
1var jQuery = function( selector, context ) {
2 return new jQuery.fn.init( selector, context );
3},
可以看到一个构造函数jQuery.fn.init
,通过new
这个构造函数可以生成jQuery实例。
打印这个构造函数的原型看看有些什么东西?
1console.log(Object.keys(jQuery.fn.init.prototype));
打印结果看图:
在jQuery.fn.init
的prototype
中有着封装的方法可供实例调用。
上面返回的构造函数jQuery.fn.init
也可以看成是jQuery.fn
的init
方法。另外注意看上面打印截图,里面也有个init
方法:
1console.log(jQuery.fn.init.prototype.init === jQuery.fn.init) //true
这表明jQuery.fn
可以调用jQuery.fn.init
的原型链上的方法,则
1jQuery.fn.init.prototype === jQuery.fn // true
所以在jQuery
中,在原型链上绑定了很多方法,同时
1jQuery.fn === jQuery.fn.init.prototype //true
2jQuery.fn.init.prototype === jQuery.prototype //true
总结:
jQuery()
可以返回一个实例jQuery
自己也是构造函数可以被显式new
来构建实例emmm…,最后的总结这块,是看的网上的同类教程结论,我自己还没完全理清,因为后面的源码还没读呢,这里先写在这算是给后面看的时候提个醒也是个校验,可以叫带着问题去读吧,今天就先到这。