IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    JavaScript - 深浅拷贝

    Johon发表于 2022-09-02 00:00:00
    love 0
    #### 前言 **JS 中的数据类型可分为两种:** - 基本类型: `undefined` , `null` , `Boolean` , `String` , `Number` , `Symbol` - 引用类型: `Object` , `Array` , `Date` , `Function` , `RegExp` 等 **不同类型的存储方式:** - 基本类型:基本类型值在内存中占据固定大小,保存在 `栈内存` 中 - 引用类型:引用类型的值是对象,保存在 `堆内存` 中,而 `栈内存` 中存储的是对象的 `变量标识符` 以及对象在 `堆内存` 中的存储地址 **不同类型的复制方式:** - 基本类型:从一个变量向另外一个新变量复制基本类型的值,会创建这个值的一个副本,并将该副本复制给新变量 - 引用类型:从一个变量向另一个新变量复制引用类型的值,其实复制的是储存地址,最终两个变量最终都指向同一个对象 #### 深浅拷贝的区别 - 浅拷贝:仅仅是复制了引用,彼此之间的操作会互相影响 - 深拷贝:在堆中重新分配内存,不同的地址,相同的值,互不影响 #### 浅拷贝 对象的浅拷贝是属性与拷贝的源对象属性共享相同的引用(指向相同的底层值)的副本。因此,当你更改源对象或副本时,也可能导致另一个对象发生更改。与之相比,在深拷贝中,源对象和副本是完全独立的。 ##### 赋值 ```javascript title="循环赋值" function shallowClone(object) { // 只拷贝对象 if (!object) return object // 根据 object 的类型判断是新建一个数组还是对象 const newObject = Array.isArray(object) ? [] : {} // 遍历 object,并且判断是 object 的属性才拷贝 for (let key in object) { if (object.hasOwnProperty(key)) { newObject[key] = object[key] } } return newObject } const obj = { a: 'hello', b: { c: 'js', }, } const newObj = shallowClone(obj) newObj.a = 'HELLO' newObj.b.c = 'JS' console.log(obj.a) // => hello console.log(obj.b.c) // => JS ``` ##### Object.assign ```javascript title="Object.assign" const obj = { a: 'hello', b: { c: 'js', }, } const newObj = Object.assign({}, obj) newObj.a = 'HELLO' newObj.b.c = 'JS' console.log(obj.a) // => hello console.log(obj.b.c) // => JS ``` ##### 扩展运算符(...) ```javascript title="扩展运算符(...)" const obj = { a: 'hello', b: { c: 'js', }, } const newObj = { ...obj } newObj.a = 'HELLO' newObj.b.c = 'JS' console.log(obj.a) // => hello console.log(obj.b.c) // => JS ``` #### 深拷贝 在 JavaScript 中,深克隆是指对一个对象或数组进行完整的拷贝,包括嵌套的对象和数组。深克隆的实现有多种方式,具体选择取决于数据结构的复杂程度和性能要求。 ##### JSON.parse(JSON.stringify(...)) ```javascript title="JSON.parse(JSON.stringify(object))" const obj = { a: 'hello', b: { c: 'js', }, } const newObj = JSON.parse(JSON.stringify(obj)) newObj.a = 'HELLO' newObj.b.c = 'JS' console.log(obj.a) // => hello console.log(obj.b.c) // => js ``` **局限性:** 会忽略 undefined 会忽略 symbol 不能序列化函数 不能解决循环引用的对象 ##### 递归 ```javascript title="递归" function deepClone(obj) { if (obj === null) return obj if (obj instanceof Date) return new Date(obj) if (obj instanceof RegExp) return new RegExp(obj) if (typeof obj !== 'object') return obj const cloneObj = new obj.constructor() for (let key in obj) { if (obj.hasOwnProperty(key)) { cloneObj[key] = deepClone(obj[key]) } } return cloneObj } const obj = { a: 'hello', b: { c: 'js', }, } const newObj = deepClone(obj) newObj.a = 'HELLO' newObj.b.c = 'JS' console.log(obj.a) // => hello console.log(obj.b.c) // => js ``` **局限性:** 有爆栈的风险 大对象性能问题 循环引用 ##### structuredClone 全局的 [structuredClone()](https://developer.mozilla.org/zh-CN/docs/Web/API/structuredClone) 方法使用[结构化克隆算法](https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Structured_clone_algorithm)将给定的值进行[深拷贝](https://developer.mozilla.org/zh-CN/docs/Glossary/Deep_copy)。 ```javascript title="structuredClone" const obj = { a: 'hello', b: { c: 'js', }, } const newObj = structuredClone(obj) newObj.a = 'HELLO' newObj.b.c = 'JS' console.log(obj.a) // => hello console.log(obj.b.c) // => js ```


沪ICP备19023445号-2号
友情链接