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] }
ES6中数组和对象的扩展运算符拷贝问题以及常用的深浅拷贝方法的更多相关文章
- ES6 的Object.assign(target, source_1, ···)方法与对象的扩展运算符
一.基本概念 Object.assign方法用来将源对象(source)的所有可枚举属性,复制到目标对象(target).它至少需要两个对象作为参数,第一个参数是目标对象,后面的参数都是源对象. Ob ...
- es6学习笔记--字符串&数值&数组&函数&对象的扩展
这几天抽空学习了es6语法,关于字符串,数值,数组,函数以及对象的扩展,看到es6标准入门这本书,里面讲的扩展特别多,我认为有几部分在项目上用不到,就挑有用的当笔记学习了. 字符串的扩展 str.in ...
- ES6 数组、对象的扩展
8. 数组的扩展 扩展运算符(...),将一个数组转为用逗号分隔的参数序列. 复制数组 const a2=[...a1] 合并数组 [...arr1, ...arr2, ...arr3]; arr1. ...
- ES6学习笔记(8)----对象的扩展
参考书<ECMAScript 6入门>http://es6.ruanyifeng.com/ 对象的扩展 1.属性名的简洁表示法 : ES6允许在代码中直接写变量,变量名是属性名,变量值是属 ...
- ES6 学习笔记之四 对象的扩展
ES6 为对象字面量添加了几个实用的功能,虽然这几个新功能基本上都是语法糖,但确实方便. 一.属性的简洁表示法 当定义一个对象时,允许直接写入一个变量,作为对象的属性,变量名就是属性名. 例1: , ...
- 小程序中监听textarea或者input输入的值动态改变data中数组的对象的值
Page({ data: { todoLists:[ { detail:"", date:"", location:"", priority ...
- 小程序开发之改变data中数组或对象的某一属性值
前言:在小程序的开发中,我们在view中便利data中数组或对象时,很多情况下需要在js中动态改变数组或者对象中某一香的属性值. 效果图: 我给大家总结了案例如下: wxml如下: <scr ...
- ES6中数组的新方法
数组的扩展 1.1扩展运算符 1.1.1:... 扩展运算符(spread)是三个点(...).它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列. <body> < ...
- ES6学习笔记(一)——扩展运算符和解构赋值
前言 随着前端工程化的快速推进,在项目中使用ES6甚至更高的ES7等最近特性早已不是什么新鲜事.之前还觉得既然浏览器支持有限,那了解一下能看懂就好,然而仅仅了解还是不够的,现在放眼望去,那些成熟框架的 ...
随机推荐
- 绕过CDN找到真实IP
现在很多大型企业都会使用CDN内容分发网络,因为CDN存在多个缓存服务点,而且会根据用户IP地址,将用户请求导向到最近的服务点上进行相应,所以得不到主服务站点的ip地址,总结学习一下绕过CDN找到真实 ...
- Android仿支付宝扣款顺序,动态改变ListView各Item次序
前言:今天遇到个需求,需要让用户动态选择语音传输方式的次序,突然想起支付宝选择扣款顺序的功能,恰好能满足需要,就花了点时间写了个demo,在此权当学习记录 先上效果图 支付宝的效果 demo的效果 思 ...
- samba服务和client挂载
服务端 1.安装samba服务 yum -y install samba 2.创建系统用户 因为Samba 服务程序的数据库要求账户必须在当前系统中已经存在,否则日后创建文件时将导致文件的权限属性混乱 ...
- 小猴打架:prufer
我们概括题意,即将n个点组成一棵树的方案数. 所以是prufer. 又因为要考虑连边顺序,因此再乘上(n-1)!. 唔...难道你们都知道为什么是(n-1)!而不是n!吗... 反正我被这个地方卡了. ...
- 甘特图 dhtmlx 插件
https://dhtmlx.com/docs/products/demoApps/advanced-gantt-chart/
- eclipse修改代码后都需要clean的解决办法
问题描述: 用STS(类似于Eclipse)正在开发一个JavaWeb项目,但不知怎么的有一天,修改完Java代码,点击运行Tomcat,发现根本没有修改.刚刚开始的时候,因为一开始没找到原因而且工期 ...
- UC
public class Test{ public static void main(String args[]){ int i[]= new int[1]; System.out.println(i ...
- 【NOIP2016提高A组模拟9.9】闭门造车
题目 自从htn体验了一把飙车的快感,他就下定决心要闭门造车!但是他两手空空怎么造得出车来呢?无奈的他只好来到了汽车零部件商店. 一走进商店,玲琅满目的各式零件看得htn眼花缭乱.但是他很快便反应过来 ...
- js 数组 splice 函数 多线程
<script type="text/javascript"> var arr = new Array(6) arr[0] = "00" arr[1 ...
- Python 爬虫十六式 - 第七式:正则的艺术
RE:用匹配来演绎编程的艺术 学习一时爽,一直学习一直爽 Hello,大家好,我是 Connor,一个从无到有的技术小白.上一次我们说到了 pyquery 今天我们将迎来我们数据匹配部分的最后一位 ...