浅拷贝与深拷贝
浅拷贝
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
//实现浅拷贝
function shallowCopy (obj){
// 只拷贝对象,基本类型或null直接返回
if(typeof obj !== 'object' || obj === null) {
return obj;
}
// 判断是新建一个数组还是对象
let newObj = Array.isArray(obj) ? []: {
};
//for…in会遍历对象的整个原型链,如果只考虑对象本身的属性,需要搭配hasOwnProperty
for(let key in obj ){
//hasOwnProperty判断是否是对象自身属性,会忽略从原型链上继承的属性
if(obj.hasOwnProperty(key)){
newObj[key] = obj[key];//只拷贝对象本身的属性
}
}
return newObj;
}
//测试
var obj ={
name:'张三',
age:8,
pal:['王五','王六','王七']
}
let obj2 = shallowCopy(obj);
obj2.name = '李四'
obj2.pal[0] = '王麻子'
console.log(obj); //{age: 8, name: "张三", pal: ['王麻子', '王六', '王七']}
console.log(obj2); //{age: 8, name: "李四", pal: ['王麻子', '王六', '王七']}
测试结果:
深拷贝
深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
function deepCopy (obj, map = new WeakMap()){
// 基本类型或null直接返回
if(typeof obj !== 'object' || obj === null) {
return obj;
}
// 判断是新建一个数组还是对象
let newObj = Array.isArray(obj) ? []: {
};
//利用map解决循环引用
if (map.has(obj)) {
return map.get(obj);
}
map.set(obj, newObj);//将当前对象作为key,克隆对象作为value
for(let key in obj ){
if(obj.hasOwnProperty(key)){
newObj[key] = deepCopy(obj[key], map); //递归
}
}
return newObj
}
// 测试
let obj1 = {
name : 'AK、哒哒哒',
arr : [1,[2,3],4],
};
let obj2=deepCopy(obj1)
obj2.name = "哒哒哒";
obj2.arr[1] = [5,6,7] ; // 新对象跟原对象不共享内存
console.log('obj1',obj1) // obj1 { name: 'AK、哒哒哒', arr: [ 1, [ 2, 3 ], 4 ] }
console.log('obj2',obj2) // obj2 { name: '哒哒哒', arr: [ 1, [ 5, 6, 7 ], 4 ] }
测试结果:
函数柯里化
函数柯里化指的是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术。
作用:可以参数复用(公共的参数已经通过柯里化预置了)和延迟执行(柯里化时只是返回一个预置参数的新函数,并没有立刻执行,在满足条件后才会执行)。
参数定长的柯里化
思路:通过函数的length属性获取函数的形参个数,形参的个数就是所需参数的个数。维护一个数组,当数组的长度与函数接收参数的个数一致,再执行该函数。
// 实现函数柯里化
function curry(fn)