深拷贝与浅拷贝【JavaScript基础面试题】

浅拷贝

对象的浅拷贝

Object.assign()

使用 Object.assign()。该函数会拷贝assign()的第二个参数,比如下例中,我们会拷贝第二个参数(也就是obj1)。

const obj1 = { a: 1, b: 2 };
const obj2 = Object.assign({}, obj1);
console.log(obj2); // { a: 1, b: 2 }

展开运算符

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

for...in循环遍历拷贝

注意,for...in 会遍历对象自身的属性,以及原型链上的属性。因此,需要通过 hasOwnProperty 判断该属性是否是自身属性。

const obj1 = { a: 1, b: 2, c: { d: 4 } };
const obj2 = {};

for (const key in obj1) {
  if (obj1.hasOwnProperty(key)) {
    obj2[key] = obj1[key];
  }
}

console.log(obj2); // { a: 1, b: 2, c: { d: 4 } }

Object.keys()循环遍历拷贝

Object.keys() 只会遍历自身属性,而不会遍历原型链上的属性。

const obj1 = { a: 1, b: 2, c: { d: 4 } };
const obj2 = {};

Object.keys(obj1).forEach(key => {
  obj2[key] = obj1[key];
});

console.log(obj2); // { a: 1, b: 2, c: { d: 4 } }

数组的浅拷贝

通过 slice() 方法拷贝

const arr1 = [1, 2, 3];
const arr2 = arr1.slice();
console.log(arr2); // [1, 2, 3]

通过 concat() 方法拷贝

const arr1 = [1, 2, 3];
const arr2 = [].concat(arr1);
console.log(arr2); // [1, 2, 3]

深拷贝

JSON.parse(JSON.stringify(obj))

它既可以拷贝对象,也可以拷贝数组但是,在以下场景中不能使用它。

1.无法拷贝函数

由于 objb 属性是一个函数,JSON在序列化的时候,会忽略函数,因此无法拷贝 b 属性。

const obj = {
  a: 1,
  b: function () {
    console.log('hello');
  },
};

const newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj); // { a: 1 }

2.无法拷贝特殊对象,如 Date 、正则表达式

const obj = {
  date: new Date(),
  regex: /test/,
};

const newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj.date); // 输出字符串,而不是 Date 对象
console.log(newObj.regex); // 输出空对象,而不是 RegExp 对象

3. 不会拷贝原型链上的属性

c 是原型链上的属性,但拷贝后的到的新对象 newObj 上没有 c 属性。

const protoObj = { c: 3 };
const obj = Object.create(protoObj);
obj.a = 1;
obj.b = 2;

const newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj.c); // undefined

4. 会忽略 symbol undefined 属性

const obj = {
  a: undefined,
  b: Symbol('test'),
};

const newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj); // 输出空对象:{}

手写一个简单的深拷贝

function deepClone(obj) {
  // 基本数据类型直接返回
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }

  // 根据输入对象的类型创建一个新的对象或数组
  let clone = Array.isArray(obj) ? [] : {};

  // 遍历对象的属性,并递归进行深拷贝
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key]);
    }
  }

  return clone;
}

// 示例
const obj = {
  a: 1,
  b: [2, 3, { d: 4 }],
  c: {
    e: 5
  }
};

const clonedObj = deepClone(obj);
console.log(clonedObj); // 输出 { a: 1, b: [2, 3, { d: 4 }], c: { e: 5 } }
console.log(clonedObj !== obj); // 输出 true

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

codereasy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值