const originArray = [1, 2, [6, 7], 3, 4, 5];let shallowCopyArr = [];let deepCopyArr = [];const originObject = { a: 1, b: {c: 3} };let shallowCopyObj = {};let deepCopyObj = {}const arrayLike = {  0: "AAA",  1: [1, 2],  2: "BBB",  length: 3};let shallowCopyArrLike = [];let deepCopyArrLike = [];

1. 浅拷贝

援用的复制
  • 浅拷贝实现:赋值操作符
  • "首层浅拷贝"实现:
    对象:遍历、Object.assign、扩大运算符
    数组(类数组对象):遍历、扩大运算符、Array.from、slice、concat、filter、map、reduce等数组办法
    (留神:所有的数组规范办法都实用于数组和类数组对象,只有concat例外, 具体应用参考js伪数组对象)

对象以遍历为例,数组以concat为例

for (const prop in originObject) {    if (originObject.hasOwnProperty(prop)) {        shallowCopyObj[prop] = originObject[prop];    }}shallowCopyObj.a = 2;shallowCopyObj.b.c = 4;shallowCopyObj  // { a: 2, b: {c: 4} }originObject    // { a: 1, b: {c: 4} }----------arrayLike[Symbol.isConcatSpreadable] = true;shallowCopyArrLike = [].concat.call(arrayLike, [7, 8]);shallowCopyArrLike.push(8)shallowCopyArrLike[2].push(3)shallowCopyArrLike   // ['AAA', [1,2,3], 'BBB', 7, 8, 3]arrayLike// const arrayLike = {//  0: "AAA",//  1: [1, 2, 3],//  2: "BBB",//  length: 3// };

2. 深拷贝

堆内存的重新分配

实现:对象、数组、类数组对象通用

  • 递归
  • JSON.parse, JSON.stringify
  • jquery.extend()

JSON.parse, JSON.stringify实现:

const originObject = { a: 1, b: { c: 3 }, d: undefined, e: Array, f: Symbol('foo') };const originArray = [1, 2, [6, 7], 3, 4, 5, undefined, Array];deepCopyObj = JSON.parse(JSON.stringify(originObject));deepCopyArr = JSON.parse(JSON.stringify(originArray));deepCopyObj.a = 2;deepCopyObj.b.c = 4;deepCopyObj  // { a: 2, b: {c: 4} }deepCopyArr  // [1, 2, [6, 7], 3, 4, 5, null, null]实现限度:1. 非数组对象的属性值为undefined、函数、Symbol值时在序列化时被疏忽, 数组中会转化为null2. 无奈解决循环援用的对象

递归实现:
关键点在于

  • 拷贝环问题
  • Date、Reg等援用类型的拷贝
  • 函数的拷贝

(1) 解决拷贝环问题: 应用Map/WeakMap,举荐应用WeakMap

const obj = {    a:1,    c: [1,2],    d: {        e: 1,    },    f: null,};obj.g = obj;function isObject(target) {  return (typeof target === 'object' || typeof target === 'function') && target !== null}function clone(target) {    // WeakMap对键名的援用为弱援用,有利于垃圾回收机制    const vm = new WeakMap();    function deepClone(target) {        if (isObject(target)) {            if (vm.has(target)) return vm.get(target);            let cloneTarget = Array.isArray(target) ? [] : {};            vm.set(target, cloneTarget);            for (const key in target) {                cloneTarget[key] = deepClone(target[key]);            }            return cloneTarget;        } else {            return target;        }    };    return deepClone(target);}const obj1 = clone(obj)obj1.c[1] = 5;obj1.f = [1,2];console.log(obj1)  // {a: 1, c: [1,5], d: {e: 1}, f: [1,2], g: {...} }

(2) Date、Reg等援用类型的拷贝
应用constructor/Object.prototype.toString.call判断类型,依据不同援用类型做相应解决
未完待续........

(3) 函数、不可枚举属性等的拷贝
有这工夫钻研不如应用现成的工具库lodash.cloneDeep