ES6中数组和对象的扩展运算符拷贝问题以及常用的深浅拷贝方法
在ES6中新增了扩展运算符可以对数组和对象进行操作。有时候会遇到数组和对象的拷贝,可能会用到扩展运算符。那么这个扩展运算符到底是深拷贝还是浅拷贝呢?
一.、使用扩展运算符拷贝
首先是下面的代码。
let a = [1,2,3]; let b = [...a];
a == b // false
结果是false,这是很容易知道的,毕竟这个赋值操作符是由区别的。接下来将数组的只进行改变,又会怎样呢;
let a = [1,2,3]; let b = [...a]; a[0] = 11; console.log(a); // [ 11, 2, 3 ] console.log(b); // [ 1, 2, 3 ]
发现a的值发生改变之后b的值并没有发生改变。所以就是深拷贝了吗?别急,接下来将数组中的元素设为引用类型。
let a = [1,2,[1,2,3]]; let b = [...a]; a[2][1] = 11; console.log(a); // [ 1, 2, [ 1, 11, 3 ] ] console.log(b); // [ 1, 2, [ 1, 11, 3 ] ]
console.log(a[2] === b[2]); // true
这次的结果就有意思了,如果改变数组中的引用类型的元素中的值,此时a和b的值都会改变,并且a和b中的引用类型全等,也就是说地址是相同的。那么为什么是这样的呢?
二.、原因
首先此分析仅为本人目前的认知。
对于数组中的扩展运算符只是一个浅拷贝,仅对引用类型数据的第一层进行了拷贝,而倘若再深的层次就不会进行拷贝。
另外对象的扩展运算符和数组是一样的。
let a = { name : "Jyy", msg : { age : 29 } } let b = {...a}; console.log(a == b); // false console.log(a.msg == b.msg); // true; a.msg = { age : "28" } console.log(a); // { name: 'Jyy', msg: { age: '28' } } console.log(b); // { name: 'Jyy', msg: { age: 29 } }
三、深拷贝和浅拷贝的方法
1.浅拷贝方法
上面的例子已经看出来es6中的扩展运算符仅仅对引用类型进行了第一层的拷贝。除了es6的扩展运算符还有其他方法
对象:
使用Object.assign()
Object.assign()用于对象的合并,如果第一个参数为{},则可对后面的对象参数进行拷贝
let a = { name : "Jyy", msg : { age : 29 } } let b = Object.assign({},a); console.log(a == b); // false console.log(a.msg == b.msg); // true; a.msg = { age : "28" } console.log(a); // { name: 'Jyy', msg: { age: '28' } } console.log(b); // { name: 'Jyy', msg: { age: 29 } }
数组:
数组的浅拷贝的方法很多
a.使用slice()
slice可以截取数组中部分的元素,若参数为空,则可对数组进行浅拷贝
let a = [1,2,[1,2,3]]; let b = a.slice(); console.log(a == b); // false a[2][1] = 11; a[0] = 11; console.log(a); // [ 11, 2, [ 1, 11, 3 ] ] console.log(b); // [ 1, 2, [ 1, 11, 3 ] ] console.log(a[2] == b[2]); // true
b.使用concat()
concat可以对数组进行合并,若参数为空,亦可对数组进行浅拷贝
let a = [1,2,[1,2,3]]; let b = a.concat(); console.log(a == b); // false a[2][1] = 11; a[0] = 11; console.log(a); // [ 11, 2, [ 1, 11, 3 ] ] console.log(b); // [ 1, 2, [ 1, 11, 3 ] ] console.log(a[2] == b[2]); // true
c.使用Array.from()
let a = [1,2,[1,2,3]]; let b = Array.from(a); console.log(a == b); // false a[2][1] = 11; a[0] = 11; console.log(a); // [ 11, 2, [ 1, 11, 3 ] ] console.log(b); // [ 1, 2, [ 1, 11, 3 ] ] console.log(a[2] == b[2]); // true
2.深拷贝
对于深拷贝,数组和对象的方法是一致的
a.递归方法,就是用for循环一层一层的进行拷贝,具体代码就不写了
b.JSON.parse()
这个方法通常用于调用接口传参或者是返回的字符串数据转成对象。
let a = { name : "JYY", age : "25", msg : { addr : "hebei" } } b = JSON.parse(JSON.stringify(a)); console.log(a == b); // false console.log(a.msg == b.msg); // false a.msg.addr = "chengde"; console.log(a); // { name: 'JYY', age: '25', msg: { addr: 'chengde' } } console.log(b); // { name: 'JYY', age: '25', msg: { addr: 'hebei' } }
这个方法的弊端就是undefined
、function
、symbol
会在转换过程中被忽略
let a = { name : "JYY", age : "25", msg : { addr : "hebei" }, speek : function(){ console.log(this.name); } } b = JSON.parse(JSON.stringify(a)); console.log(a); // { name: 'JYY', height: Symbol(jyy), age: undefined, msg: { addr: 'chengde' },speek: [Function: speek] } console.log(b); // { name: 'JYY', msg: { addr: 'hebei' } }
c.使用第三方插件
比如lodash的深拷贝
const _ = require("lodash"); let syb = Symbol('jyy'); let a = { name : "JYY", height: syb, age : undefined, msg : { addr : "hebei" }, speek : function(){ console.log(this.name); } } let b = _.cloneDeep(a); console.log(a == b); // false console.log(a.msg == b.msg); // false console.log(a); // { name: 'JYY', height: Symbol(jyy), age: undefined, msg: { addr: 'chengde' },speek: [Function: speek] } console.log(b); // { name: 'JYY', height: Symbol(jyy), age: undefined, msg: { addr: 'chengde' },speek: [Function: speek] }
原文地址:https://www.cnblogs.com/jyybeam/p/11831298.html
- Firefox - SVG cross domain cookie vulnerability
- 当代 Web 的 JSON 劫持技巧
- 利用特殊协议加载本地文件, 绕过 HTML5 沙箱, 打开弹窗诸事
- Nginx权限提升漏洞(CVE-2016-1247 )分析
- 初识 Fuzzing 工具 WinAFL
- 如何使用Oozie API接口向Kerberos环境的CDH集群提交Spark2作业
- 如何编译及使用TPC-DS生成测试数据
- ASP.NET MVC编程——缓存
- ASP.NET MVC编程——错误处理与日记
- Jenkins 未授权远程代码执行漏洞(CVE-2017-1000353)
- ASP.NET MVC编程——路由
- ASP.NET MVC编程——模型
- ASP.NET MVC编程——验证、授权与安全
- 如何使用SAML配置CDSW的身份验证
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 分治-芯片测试问题
- 你说啥什么?注解你还不会?
- Mybatis系列第五讲 Mapper接口多种方式传参详解、原理、源码解析
- Mybatis系列第十讲 动态SQL,这么多种你都会?
- 3D图形学线代基础
- Splash抓取jd
- codeforces 1395C(暴力枚举)
- 不到100行代码搞定Python做OCR识别身份证,文字等各种字体
- codeforces 1389B(贪心)
- 又一个自动生成项目目录组件tree-cli,快速生成Readme项目结构
- 用Vue CLI创建uni-app,摆脱HBuilder,npm命令行运行及发布
- codeforces 1133D(map+精度控制)
- 1024程序员节 | 我在腾讯自研数据库,我为技术代言
- jasmine spyOn的单步调试
- codeforces 1363C(优先队列)