完善核心函数
之前所写的核心函数,并不完善,因为部分核心方法也没有写
添加了部分原型方法后,现在可以完善一下,有一部分也是我没注意的,在此一块加上
函数的漏缺
哪一个函数的漏缺?作为参数放入核心函数中的函数
有两个点
-
函数的参数
-
函数的
this
我们填写的函数,执行时会可以收到一个参数,提供的是$对象
为的就是防止$
命名的冲突,为了这一点,官方也是提供了两种方式获取核心函数,jQuery
和$
,甚至还有一个解决命名冲突的函数noConflict()
,也就是释放$
的使用权
感觉还是不过瘾,还在函数内传给你使用权,保证获得的会是jQuery
对象,且可以自定义参数名
jQuery(function ($) {
console.log($); // jQuery
console.log(this);// document
});
对于这一点之前没有研究好,在翻阅一些老代码时发现了这种写法,为的就是防冲突,又不用写那么长的
jQuery
而另一点则是函数的this
指向,此处是指向原生的document
对象,原因也很容易理解
虽然几乎不会用,一个箭头函数就把它无视掉了
修补工程
//...
else if (isFunction(selector)) {
//[].push.call(this, document);
this.push(document);//原型方法已添加,所以可以简化一些
if (document.readyState === 'complete') {
selector.call(document, jQuery);//修改指向,加入参数
} else {
document.addEventListener('DOMContentLoaded', selector.bind(document, jQuery));//使用bind()修改绑定
}
}
//...
第二参数
第二参数主要限制第一参数的检索范围,之前没有说是因为还有一点,回退指针
主要补上这几点
- 回退指针指向
- 第二参数使用
只有一个参数时,在参数是字符串,且不是HTML结构字符串的情况下,就直接当成选择器,而不管有没有选择到的元素,这个对象的回退指针都要指向document
而第二参数,只是先按第一参数执行好,然后再从它的范围中,按第一参数的字符串来搜索元素,且对象的回退指针会指向第二参数,就不是document
了
有点绕,整理一下就是,第二参数也是一个$对象
,不过它只会存在于,这个即将返回的对象的指针当中,可以使用end()
回退
//...
//对于字符串
else if (isString(selector)) {
//新加入一条,对于纯数字,直接退出
if (isNumeric(selector)) {
return this;
}
//是否是一个HTML结构,是则无需指针,且不搭理第二参数
if (isHTML(selector)) {
const div = document.createElement('div');
div.innerHTML = selector;
this.push(...div.children);//调优
//[].push.apply(this, div.children);
} else {
//查看是否有第二个参数
if (context) {
//如果就是一个jQuery对象
if (context.jquery) {
this.prevObject = context.each((_i, value) => {
this.push(...value.querySelectorAll(selector));
});
} else {
/*
巧用返回值和this,使用this构造函数减少层间查找
利用箭头函数使内部this依然指向外部即将返回的新对象
*/
this.prevObject = this.constructor(context).each((_i, value) => {
this.push(...value.querySelectorAll(selector));
});
}
} else {
//[].push.apply(this, document.querySelectorAll(selector));
this.push(...document.querySelectorAll(selector));
//加上回退
this.prevObject = $(document);
}
}
}
其实在后续使用中发现有一个问题,关于第二参数的
实现选择器功能,依靠的是querySelector()
与querySelectorAll()
,但它们并不能用于伪类选择器
而$
中的选择器花样多,啥都行,不仅加入伪类选择器,而且还有很多自定义类型
在这里想指出的是一个判断问题
<!--三层嵌套div-->
<body>
<div>
<div>
<div>
</div>
</div>
</div>
</body>
对于这段结构,选择器的表现
//最外层的div选择到,然后在它的内部选择div,最后选择到内层的两个div
$('div', 'body>div');
这样是没问题,也没有意见,如果换成这样,差异出来了
$('div>div', 'body>div');
是怎样的差异呢?
对于div>div
选择器,在官方的表现是,只选择到最内层的那一个
而使用querySelector()
,它的想法并不一样,依然是两个,它也有自己的道理
对于第二层的div
来说,它的父元素为div
,那它本身自然也符合div>div
的条件
而官方的表现,事实上是把选择器拼接起来,然后进行选择,是符合CSS选择器
条件的
/*符合这段选择器的,只有最内层的div*/
body>div>div>div{}