JavaScript 中的浅拷贝与深拷贝

86 阅读3分钟

JavaScript 中的浅拷贝与深拷贝

拷贝是指创建一个与原对象具有相同内容的数组或对象。根据拷贝的"深度",可以将其分为浅拷贝和深拷贝两种类型。

浅拷贝

浅拷贝是创建一个新对象或数组,只复制原始对象内容的第一层属性值(对于引用类型的属性,复制的是引用地址而非实际内容)

  1. 浅拷贝的特点

    当复制一个对象的属性时,对于基本数据类型会复制其实际值。对于引用类型的属性,复制的是引用地址而非实际内容。只拷贝一层,不会递归拷贝嵌套对象

    const original = { nested: { a: 1 } };
    const copy = { ...original };
    
    // 比较嵌套对象的引用
    console.log(copy.nested === original.nested); // true
    // 证明它们引用的是同一个嵌套对象
    

    **外层对象:**由于const copy = { ...original } 创建的是全新的外层对象,所以originalcopy是两个完全独立的对象,它们的内存地址不相同。

    console.log(original === copy) // false
    

    内层引用类型属性:对于对象内部的引用类型属性(如 obj.a 是对象/数组),浅拷贝复制的是这个属性的引用地址(指针),新旧两个外层对象共享同一个嵌套对象,所以会有:

    console.log(copy.nested === original.nested); // true
    
  2. 实现浅拷贝的常用方法

    拷贝对象

    浅拷贝拷贝对象有两种方式,拓展运算符(...)Object.assign()

    const original = { a: 1, b: { c: 2 } };
    const copy = { ...original };
    
    copy.a = 10;    // 修改基本类型属性
    copy.b.c = 20;  // 修改嵌套对象(会影响原对象)
    
    console.log(original); // { a: 1, b: { c: 20 } }
    

    Object.assign()

    const original = { a: 1, b: { c: 2 } };
    const copy = Object.assign({}, original);
    
    copy.a = 10;
    copy.b.c = 20;
    console.log(original); // { a: 1, b: { c: 20 } }
    

    拷贝数组

    拷贝数组可以通过 (...)、Array.slice()Array.from()

    const original = [1, 2, { a: 3 }];
    const copy = original.slice(); // 
    const copy1 = Array.from(original);
    const copy2 = [...original]
    const copy3 = [].concat(original);
    
    console.log(copy); // [1, 2, { a: 30 }]
    console.log(copy1); // [1, 2, { a: 30 }]
    console.log(copy2); //[1, 2, { a: 30 }]
    console.log(copy3); //[1, 2, { a: 30 }]
    console.log(original); // [1, 2, { a: 30 }]
    
  3. 浅拷贝的应用场景

    确定对象没有嵌套引用需要独立拷贝时、性能要求高且能接受共享引用的场景、只需要第一层属性独立的简单情况

    如:快速创建对象副本(当不需要深度拷贝时)函数参数传递(避免直接修改输入参数)React/Vue 状态更新(触发响应式更新)

深拷贝

深拷贝会递归复制对象或数组的所有层级,创建一个完全独立的新对象,新旧对象之间不会共享任何引用。

  1. 实现方式

    JSON.parse(JSON.stringify()),使用这种无法处理函数、undefined、symbol、循环引用等

    const original = { a: 1, b: { c: 2 } };
    const copy = JSON.parse(JSON.stringify(original));
    
    console.log(copy) //{ a: 1, b: { c: 2 } }
    

    **LodashcloneDeep**方法

    const _ = require('lodash');
    const original = { a: 1, b: { c: 2 } };
    const deepCopy = _.cloneDeep(original);
    
  2. 运用场景

    当对象结构复杂,有多层嵌套,或者需要完全独立的新对象,不希望新旧对象有任何关联