返回

独家揭秘:JavaScript的深浅拷贝与巧妙运用

前端

一、浅拷贝与深拷贝的差异

在JavaScript中,对象是一种引用类型,存储在堆内存中,仅保存对象的地址,而变量则存储在栈内存中,保存着该对象的地址。当对对象进行赋值时,其实是将对象的地址赋值给变量,而不是将对象本身赋值给变量,即变量只保存了对象的引用。

浅拷贝:浅拷贝是指将一个对象的属性值拷贝到另一个对象中,但只是拷贝了属性值本身,而不会拷贝属性值所引用的对象。当对浅拷贝的对象进行修改时,只会影响该对象本身,不会影响原对象。

深拷贝:深拷贝是指将一个对象的属性值及其所引用的对象都拷贝到另一个对象中,这样两个对象完全独立,互不影响。当对深拷贝的对象进行修改时,不会影响原对象。

二、实现深拷贝的方法

1. JSON.stringify()和JSON.parse()方法

const originalObject = {
  name: "John Doe",
  age: 30,
  address: {
    street: "123 Main Street",
    city: "Anytown",
    state: "CA",
    zip: "12345",
  },
};

const deepCopy = JSON.parse(JSON.stringify(originalObject));

deepCopy.name = "Jane Doe";
deepCopy.address.city = "Newtown";

console.log(originalObject);
// { name: 'John Doe', age: 30, address: { street: '123 Main Street', city: 'Anytown', state: 'CA', zip: '12345' } }

console.log(deepCopy);
// { name: 'Jane Doe', age: 30, address: { street: '123 Main Street', city: 'Newtown', state: 'CA', zip: '12345' } }

2. 循环拷贝

const originalObject = {
  name: "John Doe",
  age: 30,
  address: {
    street: "123 Main Street",
    city: "Anytown",
    state: "CA",
    zip: "12345",
  },
};

const deepCopy = {};

for (const key in originalObject) {
  if (typeof originalObject[key] === "object") {
    deepCopy[key] = deepCopyObject(originalObject[key]);
  } else {
    deepCopy[key] = originalObject[key];
  }
}

deepCopy.name = "Jane Doe";
deepCopy.address.city = "Newtown";

console.log(originalObject);
// { name: 'John Doe', age: 30, address: { street: '123 Main Street', city: 'Anytown', state: 'CA', zip: '12345' } }

console.log(deepCopy);
// { name: 'Jane Doe', age: 30, address: { street: '123 Main Street', city: 'Newtown', state: 'CA', zip: '12345' } }

3. lodash.cloneDeep()方法

const originalObject = {
  name: "John Doe",
  age: 30,
  address: {
    street: "123 Main Street",
    city: "Anytown",
    state: "CA",
    zip: "12345",
  },
};

const deepCopy = _.cloneDeep(originalObject);

deepCopy.name = "Jane Doe";
deepCopy.address.city = "Newtown";

console.log(originalObject);
// { name: 'John Doe', age: 30, address: { street: '123 Main Street', city: 'Anytown', state: 'CA', zip: '12345' } }

console.log(deepCopy);
// { name: 'Jane Doe', age: 30, address: { street: '123 Main Street', city: 'Newtown', state: 'CA', zip: '12345' } }

三、深拷贝的应用场景

1. 克隆对象

const originalObject = {
  name: "John Doe",
  age: 30,
  address: {
    street: "123 Main Street",
    city: "Anytown",
    state: "CA",
    zip: "12345",
  },
};

const clonedObject = _.cloneDeep(originalObject);

console.log(clonedObject);
// { name: 'John Doe', age: 30, address: { street: '123 Main Street', city: 'Anytown', state: 'CA', zip: '12345' } }

2. 修改对象属性而不影响原对象

const originalObject = {
  name: "John Doe",
  age: 30,
  address: {
    street: "123 Main Street",
    city: "Anytown",
    state: "CA",
    zip: "12345",
  },
};

const clonedObject = _.cloneDeep(originalObject);

clonedObject.name = "Jane Doe";
clonedObject.address.city = "Newtown";

console.log(originalObject);
// { name: 'John Doe', age: 30, address: { street: '123 Main Street', city: 'Anytown', state: 'CA', zip: '12345' } }

console.log(clonedObject);
// { name: 'Jane Doe', age: 30, address: { street: '123 Main Street', city: 'Newtown', state: 'CA', zip: '12345' } }

3. 安全地传递对象给函数

function modifyObject(object) {
  object.name = "Jane Doe";
  object.address.city = "Newtown";
}

const originalObject = {
  name: "John Doe",
  age: 30,
  address: {
    street: "123 Main Street",
    city: "Anytown",
    state: "CA",
    zip: "12345",
  },
};

modifyObject(_.cloneDeep(originalObject));

console.log(originalObject);
// { name: 'John Doe', age: 30, address: { street: '123 Main Street', city: 'Anytown', state: 'CA', zip: '12345' } }

四、总结

深拷贝是一种在JavaScript中将对象完全复制的方法,这样两个对象完全独立,互不影响。深拷贝可以用于克隆对象、修改对象属性而不影响原对象,以及安全地传递对象给函数。

在JavaScript中,实现深拷贝的方法有很多,包括JSON.stringify()和JSON.parse()方法、循环拷贝和lodash.cloneDeep()方法。其中,lodash.cloneDeep()方法是使用最广泛的一种深拷贝方法,因为它简单易用,并且可以处理各种复杂的对象结构。