JavaScript 中浅拷贝与深拷贝的差异与实现方式整理

文章目录

  • [JavaScript 中浅拷贝与深拷贝的差异与实现方式整理](#JavaScript 中浅拷贝与深拷贝的差异与实现方式整理)

JavaScript 中浅拷贝与深拷贝的差异与实现方式整理

浅拷贝是指复制值时,满足对象A 与物件B 不同,但物件A 与物件B 有相同的属性,并且属性的原型链相同。


而深拷贝则是指在拷贝时,对象A 与对象B 不同,两者在原型链上仅是结构相同,但其属性实际的地址不同。在拷贝值时,有可能会遇到变数是多层的情境,例如是一个对象里还有对象,深拷贝的定义会是每一层的值都不会共享址(reference)。

这样听起来可能比较抽象,具体来说,以lodash 这个套件提供的效用函式为例,有分成clonecloneDeep两种不同效用函式,clone只用于浅拷贝(第一层拷贝),但cloneDeep可用于深拷贝。下面的例子说明两者的区别:

javascript 复制代码
// lodash 的浅拷贝 clone
var objects = [{ a: 1 }, { b: 2 }];
var shallow = _.clone(objects);
console.log(objects === shallow); // false
console.log(shallow[0] === objects[0]); // true

// lodash 的深拷贝 cloneDeep
var objects = [{ a: 1 }, { b: 2 }];
var deep = _.cloneDeep(objects);
console.log(objects === deep); // false
console.log(deep[0] === objects[0]); // false

1.手写浅拷贝(shallowcopy)

方法一:手动复制值

javascript 复制代码
let objA = {
  a: 1,
  b: { c: 3 },
};

let objB = { a: objA.a, b: objA.b };

console.log(objA === objB); // false
console.log(objA.b === objB.b); // true, 第二层的对象是指向相同位置

方法二:使用展开参数

javascript 复制代码
let objA = {
  a: 1,
  b: { c: 3 },
};

let objB = { ...objA };

console.log(objA === objB); // false
console.log(objA.a === objB.a); // true, 第二层的对象是指向相同位置
console.log(objA.b === objB.b); // true, 第二层的对象是指向相同位置

方法三:使用Object.assign

javascript 复制代码
let objA = {
  a: 1,
  b: { c: 3 },
};

let objB = Object.assign({}, objA);

console.log(objA === objB); // false
console.log(objA.b === objB.b); // true, 第二层的对象是指向相同位置

2.手写深拷贝(deep copy)

方法一:使用JSON.parse(JSON.stringify(...))

前置知识:

1.全局内建工具函数

JSON 是 JS 全局内建工具对象,类似于 Math

2.序列化

序列化(serialization)

就是把内存里的复杂数据结构

转换成一种 "可以存、可以传、可以写成字符串的形式"

例如内存中的对象:

javascript 复制代码
const obj = {
  name: 'Tom',
  age: 18,
  hobbies: ['code', 'music']
};

序列化后:

javascript 复制代码
{"name":"Tom","age":18,"hobbies":["code","music"]}

3.有些数据类型不能被序列化,会丢失数据

类型 结果
function 丢失
undefined 丢失
Symbol 丢失
Date 变字符串
Map / Set 变空对象
循环引用 直接报错

这个做法是先将对象用JSON.stringify序列化为string,再通过JSON.parse转换回物件。要特别注意,这做法只能用于可序列化的物件,有些无法序列化的物件例如:function、HTML 的元素,这些是无法序列化的,所以执行前,需要先确认是否可以序列化,否则在执行JSON.stringify时会失败。

javascript 复制代码
let objA = {
  a: 1,
  b: { c: 3 },
};

function deepCopy(item) {
  return JSON.parse(JSON.stringify(item));
}

let objB = deepCopy(objA);

console.log(objA === objB); // false
console.log(objA.b === objB.b); // false

方法二:使用structuredClone(value)

针对可序列化的物件,有另外一种透过JavaScript 内建的方法达成深拷贝。这种方法是structuredClone(value),用法如下。

javascript 复制代码
let objA = {
  a: 1,
  b: { c: 3 },
};

let objB = structuredClone(objA);

console.log(objA === objB); // false
console.log(objA.b === objB.b); // false

方法三:手动递归式深拷贝

初级版本:适合面试

javascript 复制代码
//目的:深拷贝,不共用地址,自己用自己的地址,确保新旧对象之间完全独立
// 递归出口
//如果不是对象数组,就直接返回,直接拿到对应的值
//如果是对象数组,就可能是嵌套的结构,就需要递归遍历,处理每一层嵌套

// 遍历
// 循环当前对象或者数组中的每一项,依次赋值返回
function deepClone(obj)
{
    // 递归出口
    if(typeof obj===null || typeof obj !== 'object') return obj;
    const clone =Array.isArray?[] :{}

    for(let key in obj)
    {
        clone[key]=deepClone(obj[key])
    }

    return clone
}

const original = {
            name: "Alice",
            age: 25,
            info: {   //information 的简写
                city: "Beijing"
            }
        };


var deep=deepClone(original);
deep.info.city="xian";
console.log(original.info.city); //Beijing
console.log(deep.info.city);// xian

解析:

  • typeof 数组 对象 null 的时候结果都是 object 所以这部分要考虑
  • 区分数组对象的原因是是因为有些方法只有数组能用,给他拷贝成了对象就用不了

拓展:

这个版本能处理普通对象和数组,但不支持循环引用和特殊对象

相关推荐
山河木马4 小时前
矩阵专题3-怎么创建投影矩阵(uProjectionMatrix)
javascript·webgl·计算机图形学
泯泷6 小时前
第 2 篇:设计第一套字节码:Opcode、Instruction 与 Constant Pool
前端·javascript·安全
泯泷6 小时前
第 1 篇:从 1 + 2 开始:亲手写出第一台 JSVM
前端·javascript·安全
朦胧之7 小时前
页面白屏卡住排查方法
前端·javascript
犇驫聊AI8 小时前
Chrome DevTools MCP + Claude Code 自定义skills生成接口代码生成器
前端·javascript
kyriewen8 小时前
别再这样写 async/await 了:我在 Code Review 中见过最多的 8 个错误
前端·javascript·面试
用户2986985301413 小时前
在 React 中使用 JavaScript 将 Excel 转换为 SVG
前端·javascript·react.js
labixiong13 小时前
手写Promise--微任务、静态方法、async/await 全搞懂(三)
前端·javascript
铁皮饭盒15 小时前
3行代码搞定页面截图,Bun.WebView真的简单
javascript
kyriewen1 天前
我手写了一个 EventEmitter,面试官追问了 6 个问题——第 4 个我没答上来
前端·javascript·面试