浅拷贝
方法一:Object.assign()
Object.assign(target, ...sources)
- 不能拷贝继承属性
- 不能拷贝不可枚举属性
- 能拷贝Symbol 类型的属性
方法二:扩展运算符
let cloneObj = { ...obj };
缺陷和 Object.assign() 一样
方法三:concat 拷贝数组
let arr = [1, 2, 3];let newArr = arr.concat();newArr[1] = 100;console.log(arr); // [ 1, 2, 3 ]console.log(newArr); // [ 1, 100, 3 ]
方法四:slice 拷贝数组
let arr = [1, 2, {val: 4}];let newArr = arr.slice();newArr[2].val = 1000;console.log(arr);
手动实现一个浅拷贝
const shallowClone = (target) => {if (typeof target === 'object' && target !== null) {const newTarget = Array.isArray(target) ? [] : {};for (let pro in target) {if (target.hasOwnProperty(pro)) {newTarget[pro] = target[pro];}}return newTarget;}return target;}
深拷贝
方法一:JSON.stringify
let obj1 = { a:1, b:[1,2,3] }let str = JSON.stringify(obj1);let obj2 = JSON.parse(str);console.log(obj2);
- 拷贝的对象如果有函数、undefined、symbol ,会被清除,键值对消失
- 拷贝的 Date 引用类型,会变成字符串
- 拷贝的 RegExp 引用类型,会变成空对象
- 拷贝的对象含有 NaN、Infinity、-Infinity 会变成null
- 不能拷贝不可枚举属性
- 不能拷贝对象的原型链
- 不能拷贝对象的循环引用
手动实现一个深拷贝
const isComplexDataType = obj => (typeof obj === 'object') && (obj !== null)const deepClone = function (obj, hash = new WeakMap()) {// 日期对象直接返回一个新的日期对象if (obj.constructor === Date) {return new Date(obj);}// 正则对象直接返回一个新的正则对象if (obj.constructor === RegExp) {return new RegExp(obj);}// 如果循环引用了就用 weakMap 来解决if (hash.has(obj)) {return hash.get(obj);}// 利用Object 的 getOwnPropertyDescriptors 方法可以获得对象的所有属性,以及对应的特性,// 结合 Object 的 create 方法创建一个新对象,并继承传入原对象的原型链;let allDesc = Object.getOwnPropertyDescriptors(obj)let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)hash.set(obj, cloneObj)for (let key of Reflect.ownKeys(obj)) {// 针对能够遍历对象的不可枚举属性以及 Symbol 类型,我们可以使用 Reflect.ownKeys 方法;cloneObj[key] = (isComplexDataType(obj[key]) && typeof obj[key] !== 'function')? deepClone(obj[key], hash): obj[key];}return cloneObj}
