文章开头第一句加入:本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
一、JS数据类型
JS数据类型分为两大类:原始值类型和引用类型 其中,原始值类型的数据值直接存储在栈中,有七大类。无所谓深拷贝浅拷贝。 引用类型因为数据相对复杂,其真实数据存储在堆中,然后将其引用地址存储在栈中。深拷贝浅拷贝都是针对引用类型数据。
二、赋值和拷贝定义
三种定义: 赋值:针对原始值类型, 浅拷贝:仅拷贝了栈中的引用地址,共享堆中的一份数据。修改会同时受到影响。 深拷贝:深度完全拷贝堆中的数据,分别在堆中存储相互独立的两份数据,各自引用地址分别指向各自独立的数据,互不影响。
三、具体实现
需要针对JS的两种数据类型,分别处理:
- 基本数据类型:不做处理,直接返回 - string, number, boolean, null, undefined, symbol, BigInt
- 引用数据类型:分别针对不同对象类型分别不同处理方式,其中Array和普通Object,Map, Set,WeakMap, WeakSet递归拷贝
- Function
- RegExp
- Date
- Object
- Array
- Map
- Set
- Weakmap
- WeakSet
const deepClone=(data)=>{
// 1. 原始值类型:不需要做处理,直接返回原始值即可
if(isPrimitives(data)) return data;
// 2. 引用类型:针对不同引用数据类型,做不同处理
const type=getDataType(data);
console.log(type)
if(type ==='Function'){
return data.bind(this,arguments);
}
if(type ==='Date'){
return new Date(date);
}
if(type ==='RegExp'){
return new RegExp(data.source)
}
if(type ==='Object'){
let result={};
for(let key in data){
if(data.hasOwnProperty(key)){
result[key]=deepClone(data[key]);
}
}
return result;
}
if(type ==='Array'){
return data.map(item => deepClone(item));
}
if(type ==='Set'||type==='WeakSet'){
let result=new data.__proto__.constructor();
for(let item of data){
result.add(deepClone(item));
}
return result;
}
if(type==='Map'||type==='WeakMap'){
// Both key or value can be any kind of data
let result=new data.__proto__.constructor();
for(let item of data){
result.set(deepClone(item[0]),deepClone(item[1]))
}
return result;
}
}
const isPrimitives=(data)=>{
// 1. Using typeof
const type=typeof data;
return type===null || (type !=='object' && type !=='function');
// 2. Using toString()
// const list= ['Null','Undefined', 'Number', 'String', 'Symbol', 'BigInt'];
// return list.includes(getDataType(data));
}
const getDataType=(data)=>{
return Object.prototype.toString.call(data).slice(8,-1);
}
/** Test */
let arr=[1,[3],5]
let arr1=deepClone(arr);
arr1[1]=2
console.log(arr,arr1);
let obj={'a':'a','b':{'bb':'bb'}}
let obj1=deepClone(obj)
obj1.b.bb='cc'
console.log(obj,obj1);
let date=new Date(628021800000)
let date1=deepClone(date)
let date2=date1; // 浅拷贝
date1.setYear(90)
console.log(date,date1,date2)
let map=new Map();
map.set('a','a')
let keyArr=[1,2];
map.set(keyArr,'b')
let map1=deepClone(map);
map1.set('a','aa')
map1.set(keyArr,'bb')
console.log(map,map1);
let set=new Set();
set.add('a')
let set1=deepClone(set);
set1.add('aa')
console.log(set,set1);