您的位置:首页 > Web前端 > JQuery

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元素)、
$("<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 源码