数组克隆方法有哪些
-
ES6展开运算符
let arr1 = [10,20,{name:'cmj'}]; let arr2 = [...arr1];
数组arr1中元素既有基本类型值,又有对象。把arr1中元素展开逐个赋值给arr2,最终arr2中元素与arr1全部相同,实现了数组的克隆。
由于数组和对象均为引用类型值,实际存储的是堆内存地址。arr2===arr1
返回false说明arr1和arr2占用了不同的堆内存,可是数组中的对象元素在克隆后仍占用同一块堆内存。像这样,只把最外层克隆,而内层与原来的共用相同的堆地址,这种克隆称为浅克隆。
相对地,如果内层(无论多少层)的引用类型值与原来的占用不同的堆地址,这样的克隆即为深克隆。
-
slice(0): 这种方式也是浅克隆
let arr1 = [10,20,{name:'cmj'}]; let arr2 = arr1.slice(0);
-
…
那深克隆如何实现呢?
- 基于JSON把对象转换为字符串,再转换回对象。
let arr2 = JSON.parse(JSON.stringify(arr1));
但这种方式有个小问题:正则对象会变为空对象{},而函数对象会变为null。
自己实现数组/对象的深克隆
function _type(value){
return Object.prototype.toString.call(value);
}
function _deepClone(obj){
// 首先进行类型判断
if(obj === null) return;
if(typeof obj === 'function') return; // 函数的深克隆没啥意义
if(typeof obj !== 'object') return obj; // 能进到这个判断里来的一定是基本类型值了
if(_type(obj) === '[object RegExp]') return new RegExp(obj); // 正则对象
if(_type(obj) === '[object Date]') return new Date(obj); // 日期对象
// 下面的这些才是正经八百的对象和数组
let newObj = new obj.constructor; // 根据传进来的obj类型,创建一个新的该类型实例
for(let key in obj){
if(!obj.hasOwnProperty(key)) break;
// newObj[key] = obj[key]; 这样实现的只有一层,是浅克隆
newObj[key] = _deepClone(obj[key]); // 用递归实现多层深克隆
}
}