深浅拷贝,温故知新

这篇具有很好参考价值的文章主要介绍了深浅拷贝,温故知新。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、深拷贝

1.1、概念

对象的深拷贝是指其属性与其拷贝的源对象的属性不共享相同的引用(指向相同的底层值)的副本。

因此,当你更改源或副本时,可以确保不会导致其他对象也发生更改;也就是说,你不会无意中对源或副本造成意料之外的更改。

在深拷贝中,源和副本是完全独立的。深拷贝与其源对象不共享引用,所以对深拷贝所做的任何更改都不会影响源对象。

1.2、实现方式:

1.2.1、使用 JSON.stringify() 将该对象转换为 JSON 字符串,然后使用 JSON.parse() 将该字符串转换回(全新的)JavaScript 对象。

前提:JavaScript 对象可以被序列化

序列化异常报错

  • 存在循环引用时,会抛出异常 TypeError ("cyclic object value")(循环对象值)
  • 存在 BigInt 类型的值时,如:{ num: BigInt(1111111111) } 会抛出 TypeError ("BigInt value can't be serialized in JSON")(BigInt 值不能 JSON 序列化).

序列化需要注意的隐式转换

  • 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中
  • undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。函数、undefined 被单独转换时,会返回 undefined,如 JSON.stringify(function(){}) or JSON.stringify(undefined).
  • 所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们。
  • Date 日期,会调用 toJSON() 将其转换为 string 字符串(同 Date.toISOString())
  • NaNInfinity 格式的数值及 null 都会被当做 null
  • Map/Set/WeakMap/WeakSet,仅会序列化可枚举的属性
  • HTML 元素对象, 会得到 {}

示例

  // 隐式转换

  JSON.stringify([new Number(1), new String("false"), new Boolean(false)]);
  // '[1,"false",false]'

  JSON.stringify({x: undefined, y: Object, z: Symbol("")});
  // '{}'

  JSON.stringify([undefined, Object, Symbol("")]);
  // '[null,null,null]'

  JSON.stringify({[Symbol("foo")]: "foo"});
  // '{}'

  JSON.stringify({[Symbol.for("foo")]: "foo"}, [Symbol.for("foo")]);
  // '{}'

  JSON.stringify(
      {[Symbol.for("foo")]: "foo"},
      function (k, v) {
          if (typeof k === "symbol"){
              return "a symbol";
          }
      }
  );

  // undefined

  // 不可枚举的属性默认会被忽略:
  JSON.stringify(
      Object.create(
          null,
          {
              x: { value: 'x', enumerable: false },
              y: { value: 'y', enumerable: true }
          }
      )
  );

  // "{"y":"y"}"

  JSON.stringify(document.body) // '{}'

  JSON.stringify(new Set([1, 2, 3])) // '{}'

  JSON.stringify(new Map([['num', 2]])) // '{}'
1.2.2、使用 window.structuredClone(),使用结构化克隆算法将给定的值进行深拷贝。

前提:可序列化的对象,且在浏览器环境和任何其他实现了 window 这样全局对象的 JavaScript 运行时的环境(structuredClone() 不是 JavaScript 语言本身的特性)

优点

  • 支持把原始值中的可转移对象转移到新对象,而不是把属性引用拷贝过去。
    • 可转移对象与原始对象分离并附加到新对象; 它们不可以在原始对象中访问被访问到。
  • 支持循环引用

补充:结构化克隆算法

  • 结构化克隆算法是用于复制复杂 js 对象的算法。
  • 它通过递归输入对象来构建克隆,同时保持先前访问过的引用的映射,以避免无限遍历循环。
  • Worker 的 postMessage()IndexedDB 存储对象时内部使用该算法。所以,也可间接的通过这2个方法实现深拷贝。

补充:可转移对象

  • 可转移的对象(Transferable object)是拥有属于自己的资源的对象,这些资源可以从一个上下文转移到另一个,确保资源一次仅在一个上下文可用。传输后,原始对象不再可用;它不再指向转移后的资源,并且任何读取或者写入该对象的尝试都将抛出异常。
  • 可转移对象通常用于共享资源,该资源一次仅能安全地暴露在一个 js 线程中。
  • 如:ArrayBuffer 是一个拥有内存块的可转移对象。当此类缓冲区(buffer)在线程之间传输时,相关联的内存资源将从原始的缓冲区分离出来,并且附加到新线程创建的缓冲区对象中。原始线程中的缓冲区对象不再可用,因为它不再拥有属于自己的内存资源了。

异常报错

  • Function 对象是不能被结构化克隆算法复制的,抛出 DATA_CLONE_ERR 异常,如:structuredClone(function fn() {})
  • Symbol 不能被结构化克隆算法复制的,抛出 DATA_CLONE_ERR 异常,如:structuredClone({s: Symbol(1)})
  • HTML 元素对象,抛出 DATA_CLONE_ERR 异常,如:structuredClone(document.body)

隐式转换

  • RegExp 对象的 lastIndex 字段不会被保留
  • 属性描述符,setters 以及 getters(以及其他类似元数据的功能)同样不会被复制。例如,如果一个对象用属性描述符标记为 read-only,它将会被复制为 read-write,因为这是默认的情况下
  • 原形链上的属性也不会被追踪以及复制

支持的js类型

  • Array、ArrayBuffer、Boolean、DataView、Date、Map、Set、String、TypedArray
  • Error 类型(仅限部分 Error 类型)。
  • Object 对象:仅限简单对象(如使用对象字面量创建的)。
  • 除 symbol 以外的基本类型。
  • RegExp:lastIndex 字段不会被保留。

支持的 Error类型

  • Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError(或其他会被设置为 Error 的)。

示例

// 循环引用
const original = { name: "MDN" };
original.itself = original;

// clone
const clone = structuredClone(original);

// 验证
console.log(clone !== original) // true
console.log(clone.name === "MDN") // true
console.log(clone.itself === clone) // true


const get = { get foo() { return 'bar' } }
console.log(get.foo) // 'bar'


class MyClass { 
  foo = 'bar' 
  myMethod() { /* ... */ }
}
const myClass = new MyClass()

const cloned = structuredClone(myClass)
// { foo: 'bar' }

cloned instanceof myClass // false
1.2.3、 使用js库

比如 lodash 中的 cloneDeep() 方法

该方法会递归拷贝 value。

clone 方法参考自 结构化克隆算法 以及支持 arraysarray buffersbooleansdate objectsmapsnumbersObject 对象, regexes, sets, strings, symbols, 以及 typed arraysarguments 对象的可枚举属性会拷贝为普通对象。 一些不可拷贝的对象,例如 error objectsfunctions, DOM nodes, 以及 WeakMaps 会返回空对象。

参考:MDN

  • 深拷贝
  • JSON.stringify()
  • 结构化克隆算法
  • 可转移对象

2、浅拷贝

2.1、概念

对象的浅拷贝是其属性与拷贝源对象的属性共享相同引用(指向相同的底层值)的副本。

因此,当你更改源或副本时,也可能导致其他对象也发生更改——也就是说,你可能会无意中对源或副本造成意料之外的更改。

在浅拷贝中,对源或副本的更改可能也会导致其他对象的更改(因为两个对象共享相同的引用)。

2.2、实现方式

在 js 中,所有标准的内置对象进行操作:...展开语法、Array.prototype.concat()Array.prototype.slice()Array.from()Object.assign()Object.create(),创建的都是浅拷贝而不是深拷贝。

参考:MDN 浅拷贝

最后,感谢您阅读这篇博客!希望本文能够为您提供有价值的信息和启示。

如果您对本文的内容有任何疑问或建议,请随时在评论区留言,我会尽快回复您。文章来源地址https://www.toymoban.com/news/detail-438618.html

到了这里,关于深浅拷贝,温故知新的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 温故知新之:代理模式,静态代理和动态代理(JDK动态代理)

    代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。 静态代理 是一种代理模式的实现方式,它在编译期间就已经确定了代理对象,需要为每一个被代理对象创建一个代理类。静态代理的实现比较简单,但是每个被代理对象都需要创建

    2024年02月11日
    浏览(48)
  • Linux学习第31天:Linux MISC 驱动实验:温故知新

    Linux版本号4.1.15   芯片I.MX6ULL                                     大叔学Linux    品人间百味  思文短情长           学习是一个不断重复的过程。只有不断的使用、修正,才能越记越牢。将学习到的新的知识点应用到以往的项目经验中,才能不断提升自我,长此以往

    2024年02月06日
    浏览(43)
  • .net 温故知新【17】:Asp.Net Core WebAPI 中间件

    到这篇文章为止,关于.NET \\\"温故知新\\\"系列的基础知识就完结了,从这一系列的系统回顾和再学习,对于.NET core、ASP.NET CORE又有了一个新的认识。 不光是从使用,还包括这些知识点的原理,虽然深入原理谈不上,但对于日常使用也够了,我想的是知其然,知其所以然。 在实际

    2024年01月18日
    浏览(58)
  • .net 温故知新【11】:Asp.Net Core WebAPI 入门使用及介绍

    在Asp.Net Core 上面由于现在前后端分离已经是趋势,所以asp.net core MVC用的没有那么多,主要以WebApi作为学习目标。 我使用的是VS2022, .Net 7版本。 在创建界面有几项配置: 配置Https 启用Docker 使用控制器 启用OpenAPI支持 不使用顶级语句 其中配置Https 是WebApi是否使用https协议,启

    2024年02月07日
    浏览(46)
  • 前端面试题(第三弹)——js对象的基本方法和深浅拷贝

    第一种 第二种 1.configurable:属性是否可以通过delete删除,默认值为true。 2.enumberable:属性是否可以通过for in 进行循环返回,默认值为true。 3.writable:属性是否可被修改,默认值为true。 4.value:属性实际的值,默认为undefined。 访问器属性有四个属性类型,也是使用Object.defin

    2024年02月13日
    浏览(46)
  • 温故而知新-JVM垃圾收集器

    标记-清除 复制算法 标记-整理 现在垃圾收集器均采用分代收集策略,新生代由于98%的对象都是朝生夕死,复制算法更合适,只复制还存活的对象,工作量小,所以效率高。显然复制算法不适合老年代,因为老年代中的对象大部分是大对象,且长时间存活,复制算法效率太低

    2024年02月15日
    浏览(67)
  • 【温故而知新】HTML5 WebSocket

    HTML5是HTML的最新版本,它引入了许多新的元素和功能,以适应现代网页开发的需求。以下是HTML5的一些主要特点: 新增语义元素 :HTML5引入了许多新的语义元素,如 header、footer、article、section 等,这些元素有助于提高网页的结构化和可访问性。 媒体支持 :HTML5引入了 audio 和

    2024年01月18日
    浏览(50)
  • 【温故而知新】JavaScript的继承方式有那些

    JavaScript使用原型链来实现继承。每个JavaScript对象都有一个原型(prototype)属性,它指向另一个对象。当我们访问一个对象的属性时,如果该对象没有该属性,JavaScript会沿着原型链向上查找,直到找到该属性或者到达原型链的顶部(即Object.prototype)。 有多种方式来实现继承

    2024年01月19日
    浏览(56)
  • 【温故而知新】JavaScript类、类继承、静态方法

    JavaScript是一种广泛使用的编程语言,主要用于Web开发。它是一种脚本语言,这意味着它不需要像编译语言那样预先编译,而是在运行时解释和执行。JavaScript可以直接在浏览器中运行,这使得它在前端开发中特别重要,可以用于动态生成和更改网页内容、响应用户交互、发送

    2024年01月22日
    浏览(50)
  • 【温故而知新】HTML5 应用程序缓存

    HTML5是HTML的最新版本,它引入了许多新的元素和功能,以适应现代网页开发的需求。以下是HTML5的一些主要特点: 新增语义元素 :HTML5引入了许多新的语义元素,如 header、footer、article、section 等,这些元素有助于提高网页的结构化和可访问性。 媒体支持 :HTML5引入了 audio 和

    2024年01月23日
    浏览(73)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包