深拷贝与浅拷贝

深拷贝和浅拷贝都只针对引用数据类型,浅拷贝会对对象逐个成员依次拷贝,但只复制内存地址,而不复制对象本身,新旧对象成员还是共享同一内存;深拷贝会另外创建一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

区别:浅拷贝只复制对象的第一层属性,而深拷贝会对对象的属性进行递归复制。

JS浅拷贝

当把一个对象赋值给一个新的变量时,赋的对象是该对象在栈中的地址,而不是堆中的数据。也就是新旧两个对象指的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,两个对象联动的会一起改变。

`var obj1 = {'name' : 'zhangsan','language' : [1,[2,3],[4,5]],
};
var obj2 = obj1;
obj2.name = "lisi";
obj2.language[1] = ["二","三"];
console.log('obj1',obj1)
console.log('obj2',obj2)`

浅拷贝是按位拷贝对象,它会创建一个新对象,对原有对象的成员进行依次拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是内存地址。因此如果新对象中的某个对象成员改变了地址,就会影响到原有的对象。

//手写浅拷贝
function shallowCopy(obj1) {let obj2 = Array.isArray(obj1) ? [] : {}for (let i in obj1) {obj2[i] = obj1[i]}return obj2
}
var obj1 = {'name' : 'zhangsan','language' : [1,[2,3],[4,5]],
};
var obj2 = shallowCopy(obj1);
obj2.name = "lisi";
obj2.language[1] = ["二","三"];
console.log('obj1',obj1)
console.log('obj2',obj2)

浅拷贝的实现

(1)Object.assign()
Object.assign()方法可以把源对象自身的任意多个的可枚举属性拷贝给目标对象,然后返回目标对象,但是Object.assign()进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。此方法对于Array和Object均可适用。

var obj1 = {'name' : 'zhangsan','language' : [1,[2,3],[4,5]],
};
var obj2 = Object.assign({}, obj1);
obj2.name = "lisi";
obj2.language[1] = ["二","三"];
console.log('obj1',obj1)
console.log('obj2',obj2)

(2)Array.prototype.concat()和Array.prototype.slice()
Array.prototype.concat()和Array.prototype.slice()均为Array原型上的方法,只适用于Array。

var arr1 = [1,3,{user: 'aaa'
}]
var arr2 = arr1.concat();
arr2[0] = '一';
arr2[2].user = 'AAA';
console.log('arr1',arr1)
console.log('arr2',arr2)var arr1 = [1,3,{user: 'aaa'
}]
var arr2 = arr1.slice();
arr2[0] = '一';
arr2[2].user = 'AAA';
console.log('arr1',arr1)
console.log('arr2',arr2)

JS深拷贝

对对象的属性中所有引用类型的值,遍历到是基本类型的值为止。

深拷贝实现方式

(1)JSON.parse(JSON.stringify())

原理:用JSON.stringify()将对象转成字符串,再用JSON.parse()把字符串解析成对象

var obj1 = {'name' : 'zhangsan','language' : [1,[2,3],[4,5]],
};
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = "lisi";
obj2.language[1] = ["二","三"];
console.log('obj1',obj1)
console.log('obj2',obj2)


缺点:这种方法可以实现数组和对象和基本数据类型的深拷贝,但不能处理函数。因为JSON.stringify()方法是将一个javascript值转换我一个JSON字符串,不能接受函数。其他影响如下:

  • 如果对象中有时间对象,那么用该方法拷贝之后的对象中,时间是字符串形式而不是时间对象
  • 如果对象中有RegExp、Error对象,那么序列化的结果是空
  • 如果对象中有函数或者undefined,那么序列化的结果会把函数或undefined丢失
  • 如果对象中有NAN、infinity、-infinity,那么序列化的结果会变成null
  • JSON.stringfy()只能序列化对象的可枚举自有属性,如果对象中有是构造函数生成的,那么拷贝后会丢弃对象的constructor
  • 如果对象中存在循环引用也无法正确实现深拷贝

手写深拷贝函数
通过递归实现深拷贝

function deepCopy(obj, parent = null) {let resultlet _parent = parentwhile(_parent) {if (_parent.originalParent === obj) {return _parent.currentParent}_parent = _parent.parent}if (obj && typeof(obj) === 'object') {if (obj instanceof RegExp) {result = new RegExp(obj.source, obj.flags)} else if (obj instanceof Date) {result = new Date(obj.getTime())} else {if (obj instanceof Array) {result = []} else {let proto = Object.getPrototypeOf(obj)result = Object.create(proto)}for (let i in obj) {if(obj[i] && typeof(obj[i]) === 'object') {result[i] = deepCopy(obj[i], {originalParent: obj,currentParent: result,parent: parent})} else {result[i] = obj[i]}}}} else {return obj}return result
}
var obj1 = {x: 1
}//试调用
function construct(){this.a = 1,this.b = {x:2,y:3,z:[4,5,[6]]},this.c = [7,8,[9,10]],this.d = new Date(),this.e = /abc/ig,this.f = function(a,b){return a+b},this.g = null,this.h = undefined,this.i = "hello",this.j = Symbol("foo")
}
construct.prototype.str = "I'm prototype"
var obj1 = new construct()
obj1.k = obj1
obj2 = deepCopy(obj1)obj2.b.x = 999
obj2.c[0] = 666console.log('obj1', obj1)
console.log('obj2', obj2)

函数库
也可以使用一些函数库,比如函数库lodash,也有提供_.cloneDeep用来做深拷贝;

var _ = require('lodash');
var obj1 = {a: 1,b: { f: { g: 1 } },c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);
// false

详解JS深拷贝与浅拷贝相关推荐

  1. python获取mysql中的数据供js调用_详解js文件通过python访问数据库方法

    我来教你 js文件怎么通过python访问数据库,希望能够为你带来帮助. 1.如果是要提交表单内容给 服务器的 python 处理,那么只需要在表单 里面的 action 填写服务端的处理路由就可以了 ...

  2. socket服务器断开消息,详解JS WebSocket断开原因和心跳机制

    1.断开原因 WebSocket断开的原因有很多,最好在WebSocket断开时,将错误打印出来. ws.onclose = function (e) { console.log('websocket ...

  3. php js实现流程图,详解js中构造流程图的核心技术JsPlumb(2)_javascript技巧

    前言:上篇详解js中构造流程图的核心技术JsPlumb介绍了下JsPlumb在浏览器里面画流程图的效果展示,以及简单的JsPlumb代码示例.这篇还是接着来看看各个效果的代码说明. 一.设置连线的样式 ...

  4. 详解js对称加密和非对称加密

    详解js对称加密和非对称加密 https保证数据在传输过程中不被窃取和篡改,从而保证传输安全 1.加密 对称加密:产生一个密钥,可以用其加密,可以用其加密,也可以用其加解密. 这个密钥可以是任何东西, ...

  5. 详解 js 函数中的 arguments

    详解 js 函数中的 arguments 1.什么 arguments 简单来说:arguments 是一个对应于传递给函数的参数的类数组对象 arguments 对象是所有(非箭头)函数中都可用的局 ...

  6. 详解JS原型链与继承

    详解JS原型链与继承 JavaScript 目录 摘自JavaScript高级程序设计: 概念 确定原型和实例的关系 原型链的问题 借用构造函数 组合继承 原型继承 寄生式继承 寄生组合式继承 new ...

  7. 详解js中的继承(一)

    详解js中的继承(一) 前言 准备知识 1.构造函数,实例 2.原型对象 3.构造函数,原型对象和实例的关系 继承 原型链 小结 前言 通过[某种方式]让一个对象可以访问到另一个对象中的属性和方法,我 ...

  8. linux 弹出窗口,实现弹出窗口的window.open用法详解(js代码)

    实现弹出窗口的window.open用法详解(js代码) [1.最基本的弹出窗口代码] 其实代码非常简单: 因为这是一段javascripts代码,所以它们应该放在 cript">标签 ...

  9. js深拷贝和浅拷贝的区别

    js深拷贝和浅拷贝的区别 如何来区分深拷贝和浅拷贝,其实简单,例如: 就是我声明一个obj对象,如何让var a直接等于obj,然后有在obj新增个fun,此时的a也会随着新增个fun,相同a新增数据 ...

最新文章

  1. 初试BMap时出现BMap is not defined错误(HTML页面)
  2. VTK:相互作用之RubberBandZoom
  3. WinPcap获取网卡的更多信息
  4. MySQL命令行导出数据库
  5. 经典重温:FAIR提出SlowFast,用双分支非对称网络处理不同采样率的视频!代码开源!...
  6. ActiveReports 报表应用教程 (9)---交互式报表之动态排序
  7. java基础----Serializable的使用---- http://www.cnblogs.com/huhx/p/serializable.html
  8. (Quicker)懒人福利:鼠标快捷操作工具箱
  9. .net框架笔记(四)
  10. 联想ghost重装系统_【一键ghost装系统教程】一键ghost重装系统_一键ghost安装教程...
  11. 红旗Linux9不让登录wechat,关于网页版微信无法登陆以及wechat全平台使用的问题
  12. DeepMind 联合创始人加盟 Google AI【智能快讯】
  13. 三分子模型(trimolecular model)
  14. python计算方差的置信区间_python计算置信区间
  15. 读书笔记:《人类简史:从动物到上帝》
  16. 白帽子挖洞第II篇作业--xray+fofa主动扫描
  17. 疯狂的Google之各种传说
  18. PHP+ mysql实现注册登录功能
  19. 2021-05-26
  20. vue+echarts地图下钻(全国-省-市)

热门文章

  1. 【文献调研】FiT新能源上网补贴价格和电力现货市场价格的对比(以澳大利亚和法国为例)
  2. phpwind漏洞与修复方
  3. 人工智能磁性象棋盘来了 带你上演现实版巫师棋
  4. 用Python计算利率,告诉你亏了多少?
  5. 考会计中级职称能用计算机,2020年中级会计考试可以带计算器吗?
  6. 【软件工程】软件的本质
  7. project中如何设置非标准工作时间
  8. 重置:毕业礼包论文查重
  9. 基于PyQt5的图形化界面开发——模拟医院管理系统
  10. 基于C# .NET的常用快递接口调用代码实例