数组和对象是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组。一旦修改复制对象就会修改到原来的数组,所以深拷贝是很有必要的。
扩展运算符是三个点 ...,可以将数组转换为用逗号分隔的参数序列,
let arr=[1,2,3,4,5,6]; let arr1=[...arr]; arr1[0]=8; console.log(arr);//[1,2,3,4,5,6] console.log(arr1);//[8,2,3,4,5,6]concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。 语法:arrayObject.concat(arrayX,arrayX,......,arrayX)
slice() 方法可从已有的数组中返回选定的元素。 语法:arrayObject.slice(start,end)
let arr=[1,2,3,4,5,6]; let arr1=arr.concat(); arr1[0]=8; console.log(arr);//[1,2,3,4,5,6] console.log(arr1);//[8,2,3,4,5,6] let arr=[1,2,3,4,5,6]; let arr1=arr.slice(0); arr1[0]=8; console.log(arr);//[1,2,3,4,5,6] console.log(arr1);//[8,2,3,4,5,6]包括 JSON.parse(JSON.stringify(obj))、 扩展运算符 ...和 递归
如果对象的属性是函数类型的话, JSON.parse(JSON.stringify(object))会自动过滤,所以需要使用扩展运算符,或者递归
function deepClone(source){ const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象 for(let keys in source){ // 遍历目标 if(source.hasOwnProperty(keys)){ if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下 targetObj[keys] = source[keys].constructor === Array ? [] : {}; targetObj[keys] = deepClone(source[keys]); }else{ // 如果不是,就直接赋值 targetObj[keys] = source[keys]; } } } return targetObj; }扩展运算符背后调用的是遍历器接口(Symbol.iterator),如果一个对象没有部署这个接口,就无法转换。 扩展运算符的应用:
复制数组,对象合并数组将字符串转换为真正的数组实现了Iterator接口的对象,都可以使用扩展运算符转为真正的数组,对于没有实现Iterator接口的类数组可以使用Array.from() 转换为真正的数组 所谓类数组,本质特征只有一点,即必须有 length 属性,因此,任何有 length 属性的对象,都可以使用 Array.from 方法转换为真正的数组,而此时扩展运算符就无法转换。遍历器 Iterator 是一种接口,为各种不同的数据结构提供了统一的访问机制,任何部署了Iterator 接口的数据结构,都可以完成遍历操作。主要供 for…of 消费。 原生具备Iterator接口的对象有:Array、Map、Set、String、TypedArray、函数的 arguments 对象、NodeList 对象