jQuery源码剖析--jQuery入口函数-init实现

时间:2022-11-28 00:03:20

通过$工厂,最终到达了init构造函数,所有实例的初始化过程都在这里实现,所以把这里称之为入口函数。

jQuery入口函数-init实现:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<a class="a">1</a>
<a class="a">2</a>
<a class="a">3</a>
<a class="a">4</a>
</div>
<script>
/*
* jq入口对不同参数处理的规律:
* 1、传入null、undefined、0、NaN、''返回空对象( 即空实例 )
* 2、传入字符串,那么需要判断是html片段 还是 其它,
* 如果是片段,则创建对应的DOM,然后添加到实例身上;
* 否则按照选择器获取页面中的DOM,然后把获取到的DOM添加到实例身上。
* 3、如果是数组或许伪数组,那么把每一项分别添加到实例身上。
* 4、除了上面的数据类型,剩余的,统一添加到实例身上。
* */


// 判断是不是html片段
init.isHTML = function (html) {

// 如果是空类型的,直接返回false
if (!html) {
return false;
}

// 如果字符串的第一个字母是<,最后一个字母是>,并且length >= 3,就可以认为是html片段。
if (html.charAt(0) == '<' && html.charAt(html.length - 1) == '>' && html.length >= 3) {
return true;
}

return false;
};

// 去掉字符串首尾空白字符
init.trim = function (str) {

// 不是字符串就不处理了
if (typeof str !== 'string') {
return str;
}

// 优先使用内置的trim方法
if (str.trim) {
return str.trim();
}

// 把首尾空白字符替换为空,然后返回
return str.replace(/^\s+|\s+$/g, '');
};

// 判断是不是函数
init.isFunction = function (fn) {

if (typeof fn == 'function') {
return true;
}

return false;
},

// 判断是不是window
init.isWindow = function (w) {

if (w.window == w) {
return true;
}

return false;

},

// 判断是不是伪数组或真数组
init.isLikeArray = function( arr ) {

// 过滤函数和window,以及非对象的其他数据
if ( init.isFunction( arr ) || init.isWindow( arr ) || typeof arr !== 'object' ) {
return false;
}

// 判断是不是真数组
if ( ({}).toString.call( arr ) == '[object Array]' ) {
return true;
}

// 判断是不是伪数组
// arr必须有length,在这个基础上,要么length为0,要么有length - 1这个属性值
if ( ('length' in arr) && ( (arr.length === 0) || (arr.length - 1 in arr) ) ) {
return true;
}

return false;
};

function init(selector) {

// 传入null、undefined、0、NaN、''返回空对象( 即空实例 )
if (!selector) {
return this;
}

// 传入字符串,那么需要判断是html片段 还是 其它
else if (typeof selector == 'string') {

// 为了用户友好体验,先去掉首尾空白字符
selector = init.trim(selector);

// 如果是片段,则创建对应的DOM,然后添加到实例身上,
// 如果字符串的第一个字母是<,最后一个字母是>,并且length >= 3,就可以认为是html片段。
if (init.isHTML(selector)) {

/*
* 创建的思路:
* 1、先创建一个临时的div容器
* 2、设置这个div的innerHTML为html片段,
* 这些片段就自动转变为了div的子元素,
* 3、然后遍历div的子元素分别添加this身上,记住给实例补充length属性值,
* 可以使用数组的push来给实例添加,同时可以使用apply简化遍历过程。
* */

var tempDiv = document.createElement('div');
tempDiv.innerHTML = selector;
[].push.apply(this, tempDiv.childNodes);
return this;
}

// 否则按照选择器获取页面中的DOM,然后把获取到的DOM添加到实例身上
else {

/*
* 实现的思路:
* 1、使用querySelectorAll获取页面中的元素
* 2、然后遍历获取到所有元素分别添加this身上,记住给实例补充length属性值,
* 可以使用数组的push来给实例添加,同时可以使用apply简化遍历过程。
* */

try {
var nodes = document.querySelectorAll(selector);
[].push.apply(this, nodes);
return this;
} catch (e) {
this.length = 0;
return this;
}
}

}

/*
* 判断是不是真假数组的思路:
* 1、先把函数和window排除掉,
* 2、然后通过toString来判断是不是真数组
* 3、否则再判断是不是伪数组
* 备注:下面的判断只用来判断是不是伪数组,不要用下面的判断条件判断真数组,
* 例如:[ 0:1, , , ] 使用下面的判断,就会得到false,造成真数组的误判。
* 3.1、 先看看这个对象有没有length属性,
* 3.2、 如果有,看看length的值是不是为0,如果为0,OK是伪数组,
* 3.3、 如果length的值不为0,看看这个数据有没有 length - 1这个属性,如果有,OK是伪数组。
* 建议把这个是否是真假数组的判断封装为一个函数,在这里调用。
* */

else if (init.isLikeArray(selector)) {

/*
* 实现的思路:
* 把真或伪数组中的每一项分别添加到实例身上,记住给实例补充length属性值,
* 可以使用数组的push来给实例添加,同时可以使用apply简化遍历过程。
* */

[].push.apply(this, selector);
}

else {
/*
* 实现的思路:
* 把这个参数直接添加到实例身上,length为1即可。
* */

this[0] = selector;
this.length = 1;
}

}
//---------------以下为测试部分------------------
// 测试html片段
/*var $spans = new init('<span>123</span>放松地放量加速离开的<span>321</span>');
console.log( $spans );
var $divs = new init('<div><span>sdsfsdfs</span><span>dgdfgdf</span></div>');
document.body.appendChild( $spans[0] );
document.body.appendChild( $divs[0] );*/


// 测试选择器---
/*var $as = new init('a');
console.log( $as );
document.body.appendChild( $as[0] );

var $spans = new init('span');
console.log( $spans );

var $$ = new init('##dsfsd**');
console.log( $$ );*/


// var a = new init([1,2,3]);
// console.log(a);
var a = new init([1,2,3,4]);
console.log(a);
//
// console.log(init.isLikeArray([1, ,3]));
// console.log(init.isLikeArray({length: 0}));
// console.log(init.isLikeArray({length: 3, 0: 1, 1: 2, 2: 3}));
// console.log(init.isLikeArray({length: 10, 9: 999}));
//
//
// console.log(init.isLikeArray({0: 1, 1: 2, 2: 3}));
// console.log(init.isLikeArray({length:5}));
// console.log(init.isLikeArray({length:5, 0: 1, 1: 2, 2: 3}));

</script>
</body>
</html>