JS实现深拷贝、浅拷贝的方法

一、赋值、浅拷贝与深拷贝的区别

二、深拷贝的方法

1.JSON转换

var targetObj = JSON.parse(JSON.stringify(copyObj))
let arr4 = JSON.parse(JSON.stringify(arr))

缺点:

(1)如果对象里有函数,函数无法被拷贝下来
(2)无法拷贝copyObj对象原型链上的属性和方法
(3)当数据的层次很深,会栈溢出

2.普通递归函数

function deepCopy( source ) {
if (!isObject(source)) return source; //如果不是对象的话直接返回
    let target = Array.isArray( source ) ? [] : {} //数组兼容
    for ( var k in source ) {
        if (source.hasOwnProperty(k)) {
            if ( typeof source[ k ] === 'object' ) {
                target[ k ] = deepCopy( source[ k ] )
            } else {
                target[ k ] = source[ k ]
            }
        }
    }
    return target
}

function isObject(obj) {
    return typeof obj === 'object' && obj !== null
}

缺点:

(1)无法保持引用
(2)当数据的层次很深,会栈溢出

3.防栈溢出函数

function cloneLoop(x) {
    const root = {};

    // 栈
    const loopList = [
        {
            parent: root,
            key: undefined,
            data: x,
        }
    ];

    while(loopList.length) {
        // 深度优先
        const node = loopList.pop();
        const parent = node.parent;
        const key = node.key;
        const data = node.data;

        // 初始化赋值目标,key为undefined则拷贝到父元素,否则拷贝到子元素
        let res = parent;
        if (typeof key !== 'undefined') {
            res = parent[key] = {};
        }

        for(let k in data) {
            if (data.hasOwnProperty(k)) {
                if (typeof data[k] === 'object') {
                    // 下一次循环
                    loopList.push({
                        parent: res,
                        key: k,
                        data: data[k],
                    });
                } else {
                    res[k] = data[k];
                }
            }
        }
    }

    return root;
}

优点:

(1)不会栈溢出
(2)支持很多层级的数据
function copyObject(orig) {
    var copy = Object.create(Object.getPrototypeOf(orig));
    copyOwnPropertiesFrom(copy, orig);
    return copy;
  }


  function copyOwnPropertiesFrom(target, source) {
    Object
    .getOwnPropertyNames(source)
    .forEach(function (propKey) {
      var desc = Object.getOwnPropertyDescriptor(source, propKey);
      Object.defineProperty(target, propKey, desc);
    });
    return target;
  }

  var obj = {
    name: 'Jack',
    age: '32',
    job: 'developer'
  };

  var obj2 = copyObject(obj);
  console.log(obj2);
  obj.age = 39;
  obj.name = 'Tom';
  console.log(obj);
  console.log(obj2);

3. 函数库lodash

该函数库也有提供 _.cloneDeep 用来做 Deep Copy。

var _ = require('lodash');
var obj1 = {
   a: 1,
   b: { f: { g: 1 } },
   c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);
// false

浅拷贝的方法

slice()

concat()

Object.assign(target, ...sources)

{...obj} 和 [...arr]

循坏push

浅拷贝

const a = [1, {name: 'wang'}];
const b = [...a];
a[0] = 2;
a[1].name = 'li';
console.log(b)   
b // [1, { name: 'li' } ]




const a = [1,2,3];
const b = a.concat();
const c = a.slice();
a[0] = 111111;
console.log(b);
console.log(c);
b // [1,2,3]
c // [1,2,3]



// 循环push
const a = { name: 'wang' };
const b = Object.assign({}, a);
a.name = 'li';
console.log(b);
b  // { name: 'wang'}

var arr = [1,2,3,4,5]
var arr2 = copyArr(arr)
function copyArr(arr) {
    let res = []
    for (let i = 0; i < arr.length; i++) {
     res.push(arr[i])
    }
    return res
}

下面是浅拷贝一个通用方法,实现思路:遍历对象,把属性和属性值都放在一个新的对象里

var shallowCopy = function (obj) {
  // 只拷贝对象
  if (typeof obj !== 'object') return;
  // 根据obj的类型判断是新建一个数组还是一个对象
  var newObj = obj instanceof Array ? [] : {};
  // 遍历obj,并且判断是obj的属性才拷贝
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = obj[key];
    }
  }
  return newObj;
}

你可能感兴趣的:(JS实现深拷贝、浅拷贝的方法)