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等最近特性早已不是什么新鲜事.之前还觉得既然浏览器支持有限,那了解一下能看懂就好,然而仅仅了解还是不够的,现在放眼望去,那些成熟框架的 ...
随机推荐
- PAT Advanced 1041 Be Unique (20 分)
Being unique is so important to people on Mars that even their lottery is designed in a unique way. ...
- python基础语法170题
语言特性 1.谈谈对 Python 和其他语言的区别2.简述解释型和编译型编程语言3.Python 的解释器种类以及相关特点?4.说说你知道的Python3 和 Python2 之间的区别?5.Pyt ...
- Android仿支付宝扣款顺序,动态改变ListView各Item次序
前言:今天遇到个需求,需要让用户动态选择语音传输方式的次序,突然想起支付宝选择扣款顺序的功能,恰好能满足需要,就花了点时间写了个demo,在此权当学习记录 先上效果图 支付宝的效果 demo的效果 思 ...
- SQL代码
SELECT SCHEMA_NAME(SCHEMA_ID)AS ID,name as Table_name FROM sys.tables;--查询表视图 查询表视图
- 整合Spring Data JPA与Spring MVC: 分页和排序pageable
https://www.tianmaying.com/tutorial/spring-jpa-page-sort Spring Data Jpa对于分页以及排序的查询也有着完美的支持,接下来,我们来学 ...
- 洛谷P5055 可持久化文艺平衡树 (可持久化treap)
题目链接 文艺平衡树的可持久化版,可以使用treap实现. 作为序列使用的treap相对splay的优点如下: 1.代码短 2.容易实现可持久化 3.边界处理方便(splay常常需要在左右两端加上保护 ...
- 小猴打架:prufer
我们概括题意,即将n个点组成一棵树的方案数. 所以是prufer. 又因为要考虑连边顺序,因此再乘上(n-1)!. 唔...难道你们都知道为什么是(n-1)!而不是n!吗... 反正我被这个地方卡了. ...
- typing 模块
目录 typing模块 一.引言 二.typing模块的作用 三.使用typing模块 四.typing常用类型 typing模块 目录 一.引言 二.typing模块的作用 三.使用typing模块 ...
- Hibernate方法save、update、merge、saveOrUpdate及get和load的区别
在看这几个方法区别之前,有必要了解hibernate实体对象的三种状态,点击查看 http://www.cnblogs.com/Y-S-X/p/8345754.html 一.update 和 merg ...
- 【leetcode】1227. Airplane Seat Assignment Probability
题目如下: n passengers board an airplane with exactly n seats. The first passenger has lost the ticket a ...