【前端面试】深浅拷贝的方法、手写深拷贝函数

本文内容:
1、三种方法实现对象的浅拷贝
2、两种方法实现对象的深拷贝
3、实现简单的深拷贝函数

浅拷贝

方法1:Object.assign()

数组

let arr = [1, 2, 3, [10, 20, 30]];
let newArr = Object.assign(arr);

newArr[3][0] = 100;

console.log(arr);
console.log(newArr);

// [ 1, 2, 3, [ 100, 20, 30 ] ]
// [ 1, 2, 3, [ 100, 20, 30 ] ]

对象

let obj = { a: 1, b: 2, c: { m: 10, n: 20 } }
let newObj = Object.assign(obj);

newObj.c.m = 100;

console.log(obj);
console.log(newObj);

// { a: 1, b: 2, c: { m: 100, n: 20 } }
// { a: 1, b: 2, c: { m: 100, n: 20 } }

方法2:扩展运算符

数组

let arr = [1, 2, 3, [10, 20, 30]];
let newArr = [...arr];

newArr[3][0] = 100;

console.log(arr);
console.log(newArr);

// [ 1, 2, 3, [ 100, 20, 30 ] ]
// [ 1, 2, 3, [ 100, 20, 30 ] ]

对象

let obj = { a: 1, b: 2, c: { m: 10, n: 20 } }
let newObj = { ...obj };

newObj.c.m = 100;

console.log(obj);
console.log(newObj);

// { a: 1, b: 2, c: { m: 100, n: 20 } }
// { a: 1, b: 2, c: { m: 100, n: 20 } }

方法3:遍历

数组

let arr = [1, 2, 3, [10, 20, 30]];
let newArr = [];
arr.forEach((item) => {
  newArr.push(item);
})

newArr[3][0] = 100;

console.log(arr);
console.log(newArr);

// [ 1, 2, 3, [ 100, 20, 30 ] ]
// [ 1, 2, 3, [ 100, 20, 30 ] ]

对象

let obj = { a: 1, b: 2, c: { m: 10, n: 20 } }
let newObj = {};
for(let key in obj){
  newObj[key] = obj[key];
}

newObj.c.m = 100;

console.log(obj);
console.log(newObj);

// { a: 1, b: 2, c: { m: 100, n: 20 } }
// { a: 1, b: 2, c: { m: 100, n: 20 } }

深拷贝

方法1:lodash插件中 cloneDeep()

const _ = require("lodash");

let arr = [1, 2, 3, [10, 20, 30]];
let newArr = _.cloneDeep(arr);

newArr[3][0] = 100;

console.log(arr);
console.log(newArr);

// [ 1, 2, 3, [ 10, 20, 30 ] ]
// [ 1, 2, 3, [ 100, 20, 30 ] ]

方法2:JSON.parse() + JSON.stringify()

let arr = [1, 2, 3, [10, 20, 30]];
let newArr = JSON.parse(JSON.stringify(arr));

newArr[3][0] = 100;

console.log(arr);
console.log(newArr);

// [ 1, 2, 3, [ 10, 20, 30 ] ]
// [ 1, 2, 3, [ 100, 20, 30 ] ]

局限
会忽略 undefined
会忽略 symbol
不能序列化函数
不能解决循环引用的对象


手写简单的深拷贝函数

function deepClone(obj) {
  function isObject(para) {
    return (typeof para === "object" || typeof para === "function") && para !== null;
  }

  if (!isObject(obj)) {
    return obj;
  }
  let cloneObj = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key];
    }
  }
  return cloneObj;
}


let arr = [1, 2, 3, [10, 20, 30]];
let newArr = deepClone(arr);
newArr[3][0] = 100;
console.log(arr);
console.log(newArr);
// [ 1, 2, 3, [ 10, 20, 30 ] ]
// [ 1, 2, 3, [ 100, 20, 30 ] ]


let obj = { a: 1, b: 2, c: { m: 10, n: 20 } }
let newObj = deepClone(obj);
newObj.c.m = 100;
console.log(obj);
console.log(newObj);
// { a: 1, b: 2, c: { m: 10, n: 20 } }
// { a: 1, b: 2, c: { m: 100, n: 20 } }

思路

  1. 判断传入的参数是否为引用数据类型,若是简单数据类型则直接返回传入的参数;
  2. 判断传入的参数是数组还是对象,分别初始化对应的结构;
  3. 使用 for in 遍历对象,判断该属性是否为对象的自有属性obj.hasOwnProperty(key)
  4. 判断对应的属性值是否为引用数据类型,若是引用数据类型,则需要递归调用该函数,若不是则直接添加到初始化的结构上。
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值