功能描述
用过jquery的同学都知道,在$()函数中可以传递多种参数来生成jquery对象,本次就探究一下如何实现此功能.
$()函数中主要接受的参数有以下三种:字符串类型,dom对象和函数.
//1.传入字符串类型选择器
$("#container")
//2.传入字符串类型html代码
$("<div>123</div>")
//3.传入dom类型
$(document.getElementById("#xxx"))
//4.传入函数类型
$(document).ready(function(){
console.log("dom加载完毕!");
})
源码实现和解析
在上一章中我们已经学习了如何创建一个jquery对象,将其部分代码拷贝过来.在init函数中我们首先要对用户传入的两个参数content和context解析.context是上下文对象,如果用户省略不传默认为document.而content按照上面的参数类型描述主要分为字符串,函数和dom对象三种类型.
当content为字符串类型它可能有两种情况,一种是类似"<div>123<div>"的html代码,我们通过判端该字符串是否有左右<>的闭合标识符来判断该参数是否是一段html代码,如果是的话我们就要把这段html生成dom节点.另一种字符串类型是选择器,利用context.querySelectorAll()此API去寻找选择器获取dom节点.经过上述步骤的目的就是为了获取到用户想要的匹配的原生dom对象,接下来的工作便是如何将原生dom对象转化成jquery对象,实现此功能主要通过merge函数.
merge函数首先判端第一个参数是否是普通数组,如果是普通数组直接利用concat合并就可以了,否则的话第一个参数我们就把它设定为类数组对象(jquery就是一个类数组对象).通过遍历第二个数组将其元素全部加到类数组对象上并最后更新size属性返回此类数组对象,此类数组对象便是最终我们想要的jquery对象.
当content为函数类型时,我们只需要将函数收集起来放到fun_list数组中,并且监听浏览器的DOMContentLoaded事件,当浏览器中的dom元素全部加载完毕后我们循环执行fun_list数组中的函数即可.
实现源码如下:
(function(global){
var $,jQuery;
$ = jQuery = function(content,context){
return new jQuery.fn.init(content,context);
}
//收集函数
const fun_list = [];
jQuery.fn = jQuery.prototype = {
init:function(content,context){
context = context || document;
this.context = context;
if(typeof content === "string"){
let child_nodes = [];
if(content.startsWith("<") && content.endsWith(">") && content.length>2){ //创建dom节点
const DIV = context.createElement("DIV");
DIV.innerHTML = content;
child_nodes = DIV.children;
}else{ //寻找dom节点
child_nodes = context.querySelectorAll(content);
}
jQuery.fn.merge(this,child_nodes);
return this;
}else if(content.nodeType){ //判断context是不是node节点
jQuery.fn.merge(this,[content]);
return this;
}else if(typeof content === "function"){//判端context是不是函数
fun_list.push(content);
}
},
merge:function(array1,array2){
if(array1 instanceof Array){
return array1.concat(array2);
}else{
const length = array1.length || 0;
i = length;
for(j=0;j<array2.length;j++){
array1[i+j] = array2[j];
}
array1.length = length+array2.length;
return array1;
}
},
ready:function(fun){
fun_list.push(fun);
}
}
jQuery.fn.init.prototype = jQuery.fn;
global.$ = global.jQuery = $;
function domLoadComplete(){
document.addEventListener('DOMContentLoaded', function () {
document.removeEventListener('DOMContentLoaded', arguments.callee, false);
fun_list.forEach(function(fn){
fn();
})
}, false);
}
domLoadComplete();
}
)(window)
结果验证
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./lib/jquery_like.2.js"></script>
</head>
<body>
<div id="container" class="a">123</div>
<div class="a">456</div>
<div class="a">789</div>
</body>
<script>
console.log($("#container"));
console.log($(".a"));
$(document).ready(function(){
console.log("dom加载完毕!");
})
$(function(){
console.log("可以重复添加函数!");
})
</script>
</html>
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL90TUlhGdtJGb0JjY5pkMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL0IjN2ETOxUTMyATNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)