JavaScript之浅拷贝和深拷贝

一、浅拷贝

浅拷贝特点是:一是对于引用类型数据只会拷贝其引用(内存地址),不会拷贝其值;二是对于具有相同属性的两个数据源,后面的属性值会覆盖掉前面的。对象有Object.assign、展开运算等;数组有slice、concact、展开运算等

1)Object.assign

将一个或多个对象的可枚举自有属性拷贝到目标对象,并返回修改后的目标对象。也就是说返回值跟目标对象是同一个值。

var target = { a:1 };var source = { a:2, b:{ c:[1] } };
  • 引用类型数据会拷贝其引用
var ret = Object.assign(target, source);
ret.a.b.c.push(2);console.log(ret); // { a:2, b:{ c:[1,2] } }console.log(source); // { a:2, b:{ c:[1,2] } }
  • 支持拷贝Symbol类型属性
Object.assign({}, { a:1, [Symbol("b")]:2 });// logs { a:1, Symbol(b): 2 }
  • 支持对象循环引用复制
var o1 = { a:1 };var o2 = { b:2 };o1.ref = o2;o2.ref = o1;Object.assign(o1, o2);// logs { a:1, b:2, ref:[circular] }

2)展开运算符(…)

它不仅可以用于对象的展开,还可以用于数组、Set等。

var source = { a:1 };var ret = { a:2c:3, ...source };// logs { a:2, c:3 }

二、深拷贝

深拷贝会对所有数据类型的值进行复制。实现深拷贝有多种方式,常用的有JSON.parse、循环遍历对象依次拷贝属性、第三方工具(lodash等)。

function deepCopy(obj) {  // 每当递归执行deepCopy时,都会创建了一个新的作用域,  // 它跟第一次执行deepCopy时,名称相同但却不会被后面的覆盖  var res = Array.isArray(obj) ? [] : {};  for (var key in obj) {    // 忽略掉原型对象上的属性    if (obj.hasOwnProperty(key)) {      res[key] = typeof obj[key] === "object"        ? deepCopy(obj[key])        : obj[key];    }  }  return res;}

三、循环引用

循环引用就是一个对象的属性引用另一个对象,而另一个对象的属性又引用该对象,此时就形成了一个首尾相接的环状。

图片

var o1 = { a:1 };var o2 = { b:2 };o1.ref = o2; // { a:1, ref:{ b:2, ref:{...} } }o2.ref = o1; // { b:1, ref:{ a:2, ref:{...} } }

循环引用存在的问题是会导致内存占用过多,进而导致内存泄露。如何解决循环引用在拷贝时报错的问题?看看下面这个例子。

function deepCopy(obj, map = new Map()) {  // 暂且不考虑RegExp、Function等拷贝场景  var res = Array.isArray(obj) ? [] : {};  if (map.get(obj)) {    // 当进行到第三次递归时,此时map已经存在对应的value    return map.get(obj);  }  // 第一次obj: { a:1, ref:{ b:2, ... } }  // 第二次obj: { b:2, ref:{...} }  // 第三次obj: { a:1, ref:{ b:2, ... } }  map.set(obj, res);  for (var key in obj) {    if (obj.hasOwnProperty(key)) {      // 这里res的g更新会同步到Map对应的value中      res[key] = typeof obj[key] === "object"        ? deepCopy(obj[key], map)        : obj[key];    }  }  return res;}// testdeepCopy(o1);

上述代码,通过Map将已访问过的属性记录下来,如果下次再访问到之前的属性,则直接返回已存有的属性值,程序停止往下执行,deepCopy一层层出栈,直到for循环执行完,最后return最终拷贝的结果。

图片

原创文章,作者:guozi,如若转载,请注明出处:https://www.sudun.com/ask/90904.html

(0)
guozi's avatarguozi
上一篇 2024年6月7日 上午11:45
下一篇 2024年6月7日 上午11:47

相关推荐

  • 无锡网页制作公司

    你是否曾经想过,当你在浏览网页时,那些精美的页面是如何制作出来的?或许你也想拥有一个属于自己的个性化网站,但又不知道从何开始。今天,就让我们揭开这个神秘的面纱,一起来了解什么是网页…

    行业资讯 2024年3月26日
    0
  • 海外cdn有哪些优缺点呢

    CDN作为网络行业中不可或缺的重要工具,近年来一直备受关注。而随着全球化发展的趋势,海外CDN也逐渐成为各大企业必不可少的选择。那么,究竟什么是海外CDN?它又有哪些优点和缺点呢?…

    行业资讯 2024年4月19日
    0
  • dede安装初始化体验数据,debuild安装

    下载dede安装包时,由于网络原因,文件可能不完整或损坏。这种情况,建议您重新下载,并尝试在不同的网络环境下下载。 2.2 数据库连接失败 如果在数据库连接测试过程中出现失败提示,…

    行业资讯 2024年3月28日
    0
  • 被网络屏蔽的网址怎么打开呢,网络屏蔽网站怎么解除

    一些被屏蔽的网站有镜像站点,在不同的域名下提供相同的内容。您可以通过搜索引擎找到这些镜像站点,或者请您的朋友访问被屏蔽的网址。 5.联系网站管理员 如果某个网站被阻止而您确实需要访…

    行业资讯 2024年5月7日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注