在使用js实现Jquery的extend函数之前,需要知道一下几个知识点
1. 基本数据类型 和 引用数据类型
基本数据类型: null, undefined,boolean, number, string, Symbol (new in ES 6)。
引用数据类型: object,
2. 堆 和 栈
栈: 系统分配指定大小的内存,系统会自动释放资源,用于存储基本数据类型
堆: 系统动态分配大小,不会被自动释放, 用于存储引用数据类型
3. 对象的浅拷贝 和 对象的深拷贝 和 对象的赋值
浅拷贝只会拷贝对象的第一层的引用,嵌套在里面的对象引用不会被复制
深拷贝是将整个对象的每个嵌套全部都拷贝下来
赋值 let a = b, 不会拷贝这个对象,a对象中的所有依旧是指向的b对象
4. 浅拷贝实现
var obj = { name: 'abc', gender: 'male', childrens: {name: 'aa', gender: 'male'} };
function extend(target, obj) {
var result;
if (typeof target !== 'object') {
result = {};
}
else {
result = target || {};
}
if (typeof obj === 'object') {
for (let i in obj) {
if (Object.prototype.hasOwnProperty.call(obj, i)) { // 使用Object.prototype.hasOwnProperty.call是为了避免属性名冲突
result[i] = obj[i]
}
}
}
return result;
}
var obj3 = extend({}, obj);
obj3.name ="bcd";
console.log(obj); //{ name: 'abc', gender: 'male', childrens: {name: 'aa', gender: 'male'} }
console.log(obj3); //{ name: 'bcd', gender: 'male', childrens: {name: 'aa', gender: 'male'} };
5. 深拷贝实现(extend实现)
var obj = { name: 'abc', gender: [1,2,3], childrens: { name: 'aa', gender: 'male' } };
var obj2 = { key: '343', name: { name: 'bbb' } };
function isArray (arg) {
return Object.prototype.toString.call(arg) === '[object Array]' // 判断是否是数组的方法
}
function extend () {
var deep = false, result,args = arguments; //定义变量 deep为是否深拷贝, result为最终对象, args为源对象
function child_extend (target, source, deep) {
if (typeof source === 'object') {
for (var i in source) {
var temp = source[i];
// 如果source[i]依旧是对象,并且需要深拷贝
if (deep && typeof temp === 'object') {
// 初始化target[i],根据object和array进行不同的赋值
if (isArray(temp)) {
target[i] = [];
}
else {
target[i] = {}
}
child_extend(target[i], temp, deep) // 递归
}
else if (typeof temp !== 'undefined'){ // 如果source[i]是基本数据类型,且不是undefined
target[i] = temp
}
}
}
}
if (args.length > 0) {
if (typeof args[0] === 'boolean') { // 如果设置了是否深拷贝,则目标对象初始化为第二个参数, 源对象设置为第三个参数
deep = args[0];
result = args[1];
args = Array.prototype.slice.call(arguments, 2);
}
else { // 没有设置是否深拷贝的值,则目标对象初始化为第一个参数, 源对象设置为第二个参数
result = args[0];
args = Array.prototype.slice.call(arguments, 1);
}
args.forEach(element => {
// 循环遍历每一个参数
child_extend(result,element, deep)
});
}
return result;
}
var obj3 = extend(true, obj, obj2);
obj3.name.name = 'aeree';
console.log(obj3);
//{ gender: [1,2,3], childrens: { name: 'aa', gender: 'male' },key: '343', name: { name: 'bbb' } };
console.log(obj2);
// { key: '343', name: { name: 'bbb' } }
可以看到设置了深拷贝之后,目标对象的修改 不会 影响到源对象