手写深克隆
function myDeepClone(obj) {
if(!obj) return obj
if(obj instanceof Array){//数组类型
let result=[]
let len = obj.length
for(let i=0;i<len;i++){
let cur=obj[i]
if(typeof cur==='object'){
result[i]=myDeepClone(cur)
}else{
result[i]=cur
}
}
return result
}
if(obj instanceof Object){//对象类型
let result={}
for(let i in obj){
let cur=obj[i]
if(typeof cur==='object'){
result[i]=myDeepClone(cur)
}else{
result[i]=cur
}
}
return result
}
}
深克隆实现方式:1、如上的手写递归(我自己写的,可能不准确);2、JSON的序列化和返序列化:JSON.parse(JSON.stringify());3、第三方库:lodash的cloneDeep:_cloneDeep(),jQuery的extend:$.extend(true,{},obj)。
在对于对象或数组中含有函数或循环引用的情况下,使用 JSON.parse(JSON.stringify(obj))
可能会出错。因为 JSON 格式本身不支持存储函数和循环引用,所以在进行序列化和反序列化操作时会忽略掉这些内容,导致深拷贝不完整或出现异常。
面经经常提到深拷贝,浅拷贝也别忽视了,有一次就被问到了。。。
首先了解什么是浅拷贝?对于网上的众多说法,我个人觉得一下这种解释最为恰当:浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。深拷贝和浅拷贝是针对复杂数据类型(对象及数组)来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。
浅拷贝实现方式:1、展开运算符:let obj1={a:1,b:2};let obj2={...obj1};2、Object.assign(target,data1,data2...),用法:let copyData=Object.assign({},obj1);3、拷贝数组可以使用数组的slice(),如:const arr = [1, 2, { a: 3 }]; const shallowCopy = arr.slice();
试一下就知道了~
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };
obj.a=2;
console.log(shallowCopy);//{ a: 1, b: { c: 2 } }
console.log(obj);//{ a: 2, b: { c: 2 } }
obj.b.c=4;
console.log(shallowCopy);//{ a: 1, b: { c: 4 } }
console.log(obj);//{ a: 2, b: { c: 4 } }
结论就是:浅拷贝只拷贝第一层。
有特殊元素的数组去重
//输入[1,'ww',null,undefined,{},'ww',{},null]
//输出[1,'ww',null,undefined,{}]
function duplicateRemoval(arr){
let result=[]
let set=new Set()
arr.forEach(item=>{
if(typeof item==='object'){
let str=JSON.stringify(item)
if(!set.has(str)){
set.add(str)
result.push(item)
}
}else{
if(!set.has(item)){
set.add(item)
result.push(item)
}
}
})
return result;
}
上面是标准做法,我个人只能想到比较孬的做法。
function dd(arr){
const set = {};
const result = [];
arr.forEach(item => {
if (typeof item === 'object') {
const str = JSON.stringify(item);
if (!set[str]) {
set[str]=1;
result.push(item);
}
} else {
if (!set[item]) {
set[item]=1;
result.push(item);
}
}
});
return result;
};
但是!我发现这个方法有bug!像123和'123'这种,会被视为相同元素而被去重。所以还是得用上面那个方法。
闭包实现防抖功能
function antiShaking(func,delay){
let timer=null;
return function(){
const _this=this
const args=arguments
clearTimeout(timer)
timer=setTimeout(function(){
func.apply(_this,args)
},delay)
}
}