实现jQuery构造函数
现在我们想实现$()这种形式的函数调用并返回一个对象.
(function(global){
var $,jQuery;
$ = jQuery = function(){
return new jQuery.fn.init();
}
jQuery.fn = jQuery.prototype = {
init:function(){
}
}
jQuery.fn.init.prototype = jQuery.fn;
global.$ = global.jQuery = $;
}
)(window)
解析:我们把$定义为一个函数,但是怎么调用函数可以返回一个对象呢?可以想办法在函数内new一个构造函数返回.因此在jQuery的原型上创建一个init方法就将它作为jQuery的构造函数.另外还要将jQuery的原型赋值给init函数的原型.这样做的好处便是我们在jQuery.prototype上创建的各种方法是可以被new出来的jQuery实例调用的.
实现$.extend
(function(global){
var $,jQuery;
$ = jQuery = function(){
return new jQuery.fn.init();
}
jQuery.fn = jQuery.prototype = {
init:function(){
},
isPlainObject:function(data){
return Object.prototype.toString.call(data) === "[object Object]";
},
isArray:function(data){
return Object.prototype.toString.call(data) === "[object Array]";
},
isBoolean:function(data){
return typeof data === "boolean";
}
}
jQuery.extend = jQuery.prototype.extend = function(){
var target = arguments[0] || {};
var i = 1,isDeep = false,isArrayData = false;
if(typeof arguments[0] === "boolean"){ //第一个参数是boolean型
isDeep = arguments[0]?true:false;
target = arguments[1] || {};
i = 2;
}
var arr = Array.prototype.slice.call(arguments,i);
if(arguments.length == 1){
target = this;
arr = [arguments[0]];
}
arr.forEach((obj)=>{
for(let key in obj){
if(isDeep){ //深拷贝
let src = obj[key];
let des = target[key];
let copy;
if(jQuery.isPlainObject(src) || (isArrayData = jQuery.isArray(src))){
//src是数组或者对象类型
if(isArrayData){
copy = jQuery.isArray(des)?des:[]
}else{
copy = jQuery.isPlainObject(des)?des:{};
}
target[key] = jQuery.fn.extend(isDeep,copy,src); //这一句代码是精髓之处
}else{
target[key] = obj[key];
}
isArrayData = false;
}else{
target[key] = obj[key];
}
}
})
return target;
}
jQuery.fn.init.prototype = jQuery.fn;
jQuery.extend(jQuery.fn);
global.$ = global.jQuery = $;
}
)(window)
结果验证
console.log($.extend(true,{a:1,b:2,c:[1,2],e:{k:12}},{d:18,c:[3],e:{m:28,c:[1,2,34],f:{k:12}}}));
解析:$.extend实现的难点在深拷贝的处理上,当遍历源数据获取对象上的属性值时需要先判端这个值是不是对象或者数组,如果是其中之一外加上有深拷贝的标识就要开始做深拷贝的处理.我们通过判端des的类型和src的类型来确定copy的值.如果src源数据是数组,那么就要判端des是什么类型了,如果它也是数组,就要合并两个数组,把des赋值给copy.如果它不是数组,就把copy设置为空数组也能实现合并.src源数据是对象的话判端原理也如此,最后通过一句target[key] = jQuery.fn.extend(isDeep,copy,src)点睛之笔就实现了数组类型或者对象类型的合并.