Skip to content

JS 常见的拷贝方法,手写一个深拷贝

Published: at 10:54 PMSuggest Changes

常见浅拷贝方式

Object.assign 方法

let target = { a: 1 };
let object2 = { b: 2 };
let object3 = { c: 3 };
Object.assign(target, object2, object3);
console.log(target); // {a: 1, b: 2, c: 3}

手写一个

function cloneByObjAssign(params) {
  return Object.assing({}, params);
}

扩展运算符(利用了对象的结构赋值特性)方法

let obj1 = { a: 1, b: { c: 1 } };
let obj2 = { ...obj1 };
obj1.a = 2;
console.log(obj1); //{a:2,b:{c:1}}
console.log(obj2); //{a:1,b:{c:1}}
obj1.b.c = 2;
console.log(obj1); //{a:2,b:{c:2}}
console.log(obj2); //{a:1,b:{c:2}}

手写一个

function cloneByDestructuring(params) {
  return { ...params };
}

常见的深拷贝方式

大名鼎鼎的 JSON.stringify()

JSON.parse(JSON.stringify(obj)) 是目前比较常用的深拷贝方法之一,它的原理就是利用 JSON.stringify 将 js 对象序列化(JSON 字符串),再使用 JSON.parse 来反序列化 (还原)js 对象。 这个方法可以简单粗暴的实现深拷贝,但是还存在问题,拷贝的对象中如果有函数,undefinedsymbol,当使用过 JSON.stringify() 进行处理之后,都会消失。

函数库 lodash 的_.cloneDeep 方法

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

手写实现深拷贝函数

function deepClone(params) {
  if (!params && typeof params == 'object') {
    return;
  }

  let newObject = Array.isArray(params) ? [] : {};

  for (let key in params) {
    if (params.hasOneProperty(key)) {
      newObject[key] =
        typeof params[key] == 'object' ? deepClone(params[key]) : params[key];
    }
  }

  return newObject;
}

参考文章

补充

let a = { a: 1 };
let b = { ...a };
let c = Object.assign({}, a);
a.a = 2;


let d = {a: {b: {c : 1}}};
let e = {...d};
let f = Object.assign({}, d);
d.a.b.c = 2;

为什么 b 和 c 的值不会变,而 e 和 f 的值会变呢?

因为 ...Object.assign 是浅拷贝,只会拷贝一层,而 JSON.parse(JSON.stringify(obj)) 是深拷贝,会拷贝所有层级。

e 和 f 的值会变,是因为 b 和 c 是个对象,而对象是引用类型,所以 b 和 c 指向的是同一个对象,有点类似于指针,指向的是同一个引用。


Previous Post
使用 setTimeout 和 clearTimeout 模拟 setInterval 和 clearInterval
Next Post
JS 基础复习笔记(面试用)