jQuery源码阅读(二)---初识init方法
2017-07-03 17:05
495 查看
上一篇博客大体了解了jQuery整个的架构,即分成jQuery入口模块,底层支持模块以及功能模块这三个大块,并且各个模块之间有一定的联系;下来主要理解了jQuery入口模块,即jQuery对象是如何创建的,其实真正创建的jQuery实例是由jQuery.fn.init()函数创建的,并且为了使得创建的每个对象实例都拥有jQuery对象的属性和方法,即所有jQuery对象共享一份属性和方法代码,这样可大大减少所需的内存空间,利用了原生JS原型链的概念,并使得jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype。
这一次主要想重点理解init()方法中是如何来创建jQuery对象的。我们使用过jQuery库的都知道如何将DOM元素转换成jQuery对象,如何创建一个含有HTML片段的jQuery对象,如何获取到id为‘id’的jQuery对象,一个简单的$(DOM元素)、
我能想到的就是:
上面是我们利用jQuery常用的一些操作,参考了“jQuery技术内幕:深入解析jQuery架构设计与实现原理” 高云”这本书之后,里面对$()的用法还有一些补充,比如:
下面就是针对不同的参数去进行不同的操作,相当于函数的重载。
上面也可以看出参数为选择器,HTML片段或者为’body’,这些都是字符串形式,所以大方向上可以是分成下面这几种情况:
整个init函数的大体逻辑就是这样,在这里我们看到了几个jQuery静态的方法,即直接挂载在jQuery 上面的方法,而不是jQuery对象上的方法。如
上面的jQuery.isFunction(selector);
jQuery.makeArray(selector, this);
这类方法算是jQuery的底层支持模块里的工具方法了。如下图:
图片来源:
代码很少,只有一行,但是又去调了另外一个工具方法type,由这一句就可以大概知道type的作用是判断参数的类型的,下面是type的源码:
这个代码也同样很短,但是它涵盖的内容却是极其庞大的,在jQuery中用到了很多技巧。
首先是&&,||逻辑。
我们平时用到的&& 、||,主要是if判断时,将多个条件的关系用&& 或者||来组合,但在jQuery中,却更多的是用他们来表达值。比如:
这种的好处就是省去了if代码去判断,省了不少代码量,另一方面,应该也可以快速的执行。
另一个就是 jQuery中的钩子机制。
在type 这个方法中,引用了class2type这个数组,我们先来看看这个数组是什么样子。
class2type[ ‘[object Boolean]’ ] = ‘boolean’;
class2type[ ‘[object String]’ ] = ‘String’;
class2type[ ‘[object Number]’ ] = ‘Number’;
class2type[ ‘[object Function]’ ] = ‘function’;
class2type[ ‘[object Array]’ ] = ‘array’;
class2type[ ‘[object Date]’ ] = ‘date’;
class2type[ ‘[object RegExp]’ ] = ‘regexp’;
class2type[ ‘[object Object]’ ] = ‘object’;
为什么要这么做呢?如果不这么做,我们要去判断是哪一类,就需要if分支去判断,这样一步步去判断必然会导致比较慢。
而利用事先做的这个类似于表的对应关系,可以省去很多if-else操作。这就是jQuery中的钩子机制的一种,即表驱动方式。这只是钩子机制的一个小小的技巧,在别的地方还有很多其他的用法。
下来,判断类型主要有这么几种情况:
基本数据类型:null,undefined, boolean, string,number
引用数据类型:Object, Function
对于基本数据类型,typeof 就可以得到类型;
而对于Object类型, typeof并不能准确的判断出对象的具体类型,准确的方法是调用Object.prototype.toString.call()方法。
而对于Function类型,既可以用typeof操作得到,也可以调Object.toString()方法。源码如下:
这里先判断了null 和undefined类型,之后主要分成object、function类型和基本数据类型。
jQuery.merge方法
该方法主要是将两个数组进行合并并将结果保存到第一个里面。举两个例子:
下面是merge函数的源码:
这里,就先总结这么多,感觉还是要好好理解才能深入下去,不过jQuery源码再怎么说也是原生JS,只要能将原生JS的基础理解和掌握,jQuery源码还是可以看明白的。另外一点,jQuery源码里面的很多思想都是值得学习的。
这一次主要想重点理解init()方法中是如何来创建jQuery对象的。我们使用过jQuery库的都知道如何将DOM元素转换成jQuery对象,如何创建一个含有HTML片段的jQuery对象,如何获取到id为‘id’的jQuery对象,一个简单的$(DOM元素)、
$("<div></div>")和$("#id")就可以实现。这些都是init这一个函数解决的,可见,init函数里面的逻辑太庞大。下来一点一点的缕清它。
jQuery入口模块
想想我们用jQuery时,最终结果是创建了一个jQuery对象的常用方式有哪些?我能想到的就是:
//参数为函数,ready方法,等价于$().ready(function(){}) $(function(){ }) //参数为各种选择器 $('#id');$(''.class'');$(各种选择器); //参数为body $('body'); //参数为HTML代码片段 $('<div></div>'); $('<img src = '' />'); //参数为DOM元素,即将DOM元素转换为jQuery对象;或者是一个包含多个DOM元素的数组 var node = document.getELementById("id"); var nodeArray = document.getElementsByTagName("div"); $(node); $(nodeArray);
上面是我们利用jQuery常用的一些操作,参考了“jQuery技术内幕:深入解析jQuery架构设计与实现原理” 高云”这本书之后,里面对$()的用法还有一些补充,比如:
下面就是针对不同的参数去进行不同的操作,相当于函数的重载。
上面也可以看出参数为选择器,HTML片段或者为’body’,这些都是字符串形式,所以大方向上可以是分成下面这几种情况:
if(!selector) //参数为空 { return this; } if(jQuery.isFunction(selector)) //参数为函数 { //调用jQuery的ready方法 return jQuery.ready(selector); } if(typeof selector === 'string') //参数为字符串 { //里面包含了选择器,HTML片段,'body'等情况 return this; } if( selector.nodeType ) //参数为DOM元素或者DOM元素构成的数组 { return this; } if( selector.selector !== 'undefined' ) //参数为jQuery对象 { return this; } //当上面情况都没有return时,即其他情况 return jQuery.makeArray(selector, this);
整个init函数的大体逻辑就是这样,在这里我们看到了几个jQuery静态的方法,即直接挂载在jQuery 上面的方法,而不是jQuery对象上的方法。如
上面的jQuery.isFunction(selector);
jQuery.makeArray(selector, this);
这类方法算是jQuery的底层支持模块里的工具方法了。如下图:
图片来源:
jQuery底层支持模块-工具方法
可以利用源码查看工具来看工具方法的源码:地址工具方法ifFunction()
对于isFunction这个方法:代码很少,只有一行,但是又去调了另外一个工具方法type,由这一句就可以大概知道type的作用是判断参数的类型的,下面是type的源码:
这个代码也同样很短,但是它涵盖的内容却是极其庞大的,在jQuery中用到了很多技巧。
首先是&&,||逻辑。
我们平时用到的&& 、||,主要是if判断时,将多个条件的关系用&& 或者||来组合,但在jQuery中,却更多的是用他们来表达值。比如:
var s = num && num1; //如果num存在,并为真,还要判断num1的值,s就为num1的值;如果num不存在或者为假,不需要判断num1,s 就是num的值; var s1 = num2 || num3; //同理:如果num2存在,并为真,不需要后面计算num3,s就为num2的值;如果num不存在或者为假,还要判断num3,s 就是num3的值;
这种的好处就是省去了if代码去判断,省了不少代码量,另一方面,应该也可以快速的执行。
另一个就是 jQuery中的钩子机制。
在type 这个方法中,引用了class2type这个数组,我们先来看看这个数组是什么样子。
class2type[ ‘[object Boolean]’ ] = ‘boolean’;
class2type[ ‘[object String]’ ] = ‘String’;
class2type[ ‘[object Number]’ ] = ‘Number’;
class2type[ ‘[object Function]’ ] = ‘function’;
class2type[ ‘[object Array]’ ] = ‘array’;
class2type[ ‘[object Date]’ ] = ‘date’;
class2type[ ‘[object RegExp]’ ] = ‘regexp’;
class2type[ ‘[object Object]’ ] = ‘object’;
为什么要这么做呢?如果不这么做,我们要去判断是哪一类,就需要if分支去判断,这样一步步去判断必然会导致比较慢。
而利用事先做的这个类似于表的对应关系,可以省去很多if-else操作。这就是jQuery中的钩子机制的一种,即表驱动方式。这只是钩子机制的一个小小的技巧,在别的地方还有很多其他的用法。
下来,判断类型主要有这么几种情况:
基本数据类型:null,undefined, boolean, string,number
引用数据类型:Object, Function
对于基本数据类型,typeof 就可以得到类型;
而对于Object类型, typeof并不能准确的判断出对象的具体类型,准确的方法是调用Object.prototype.toString.call()方法。
而对于Function类型,既可以用typeof操作得到,也可以调Object.toString()方法。源码如下:
这里先判断了null 和undefined类型,之后主要分成object、function类型和基本数据类型。
return null == a ? a+"" : typeof a == 'object' || typeof a == 'function' ? class2Type[toString.call(a)] || 'object' : typeof a;
工具方法makeArray
该方法主要是将伪数组对象转换成数组对象。function (array, results) { var ret = results || []; if (array != null) { //array不为空、undefined时 // The window, strings (and functions) also have 'length' // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 var type = jQuery.type(array); //得到array的类型 if (array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow(array)) { //如果array不为数组,也不是对象(伪数组) push.call(ret, array); //调数组的push方法 } else { jQuery.merge(ret, array); //调jQuery的工具方法merge,该方法主要是将两个数组合并并保存到第一个数组里面 } } return ret; }
jQuery.merge方法
该方法主要是将两个数组进行合并并将结果保存到第一个里面。举两个例子:
var arr1 = ['12', 'sd', '34']; var arr2 = ['ad', '12', 'df']; $.merge(arr1, arr2); //结果为["12", "sd", "34", "ad", "12", "df"]
var t = { 0: 'li', 1: 'li', length: 2 }; $.merge(t, arr1); //
下面是merge函数的源码:
function (first, second) { var i = first.length, j = 0; if (typeof second.length === "number") { //伪数组,对象,必须有length属性,并且length属性为Number类型的值 for (var l = second.length; j < l; j++) { first[i++] = second[j]; } } else { while (second[j] !== undefined) { first[i++] = second[j++]; } } first.length = i; return first; }
这里,就先总结这么多,感觉还是要好好理解才能深入下去,不过jQuery源码再怎么说也是原生JS,只要能将原生JS的基础理解和掌握,jQuery源码还是可以看明白的。另外一点,jQuery源码里面的很多思想都是值得学习的。
相关文章推荐
- jQuery-源码阅读,init()方法
- jquery源码阅读知识储备(3)exec() 方法和match方法
- jQuery-源码阅读,使用init()而不用普通原型模式的原因
- jquery源码解析:jQuery原型方法init的详解
- jquery源码阅读知识储备(3)exec() 方法和match方法
- jQuery1.5.1 animate方法源码阅读
- jQuery源码学习8——工具方法之init
- jQuery源码阅读(六)---jQuery实例方法解析
- jquery源码阅读知识储备(5)call方法和apply方法接触
- 源代码阅读方法 jQuery源码解析 核心模块core.js
- jQuery-源码阅读,extend()与工具方法、实例方法
- jQuery-源码阅读,pushStack()入栈方法
- jQuery1.5.1 animate方法源码阅读
- Jquery源码中的Javascript基础知识(四)— jQuery.fn.init方法
- jquery源码阅读知识储备(5)call方法和apply方法接触
- jquery源码阅读知识储备(11)数学方法(四舍五入)
- jQuery 1.6 源码学习(三)——core.js[3]之init方法
- jquery源码阅读知识储备(11)javascrpt中的数字比较
- jquery源码阅读知识储备(9)javascrpt中的函数知识(待续)
- jquery源码阅读知识储备(6)typeof 和 instanceof的结合使用