前端克隆数据 --JS 深浅拷贝
START
- 番茄我又又又来写点啥啦。
- 最近敲代码,总是遇到需要修改数据,在前端展示。但是最后并不想修改原数据的情况。所以,需要涉及到数据的拷贝了,数据拷贝又分深拷贝,浅拷贝。所以写一篇文章记录一下。
- 本文仅个人的想法,能力有限,参考即可,后续对这个有更深入的理解了,再补充。
- 啰嗦一句,深拷贝浅拷贝 和 深克隆浅克隆,其实都差不多一个意思啦,看个人习惯如何称呼。
JS 的数据类型
在说深浅克隆之前,我想提一下JS的数据类型。
JS数据类型,可以大致分为两种:基本数据类型 和 引用数据类型。
基本数据类型:
- Undefined
- Null
- Boolean
- Number
- String
- 引用数据类型:
- object
- 当然 ES6 引入了一种新的数据类型 Symbol (这里暂时不讨论 Symbol)
为什么要这样区分数据类型呢?
- 因为基本数据类型数据,保存在栈内存
- 引用类型保存在堆内存中
那么为什么要分两种保存方式呢?
根本原因是在于保存在栈内存的必须是大小固定的数据,引用的类型的大小不固定,只能保存在堆内存中。但是我们可以将引用类型的地址存储在栈内存中。
文字不好理解的话,举个例子:
// 1.定义一个基本数据类型--数字类型的变量 var a = 1// 定义一个引用类型的变量 var obj = {name: "lazy_tomato" }
上面代码执行后,在内存中其实就是这样的。
知道js变量的保存方式有什么用呢?
- 看一看简单的题目就知道了。
题目一
var a = 1var b = aconsole.log('变量a为:', a, "变量b为:", b); //变量a为: 1 变量b为: 1a = 88console.log('变量a为:', a, "变量b为:", b); //变量a为: 88 变量b为: 1
题目二
var a = {name: '张三',age: 14
}var b = aconsole.log('变量a为:', a, "变量b为:", b);
//变量a为: { name: '张三', age: 14 } 变量b为: { name: '张三', age: 14 }a.name = 'lazy_tomato'console.log('变量a为:', a, "变量b为:", b);
//变量a为: { name: 'lazy_tomato', age: 14 } 变量b为: { name: 'lazy_tomato', age: 14 }
题目一中,为什么我修改a,不会修改b ?
题目二中,为什么我修改a,会同时修改b ?
正是因为题目二中,我们
var b = a
做的操作就是:声明一个变量b,b栈内存中存储的地址,和a一样,都指向
{
name: ‘张三’,
age: 14
}所以
a.name = 'lazy_tomato'
执行后 a指向堆内存中为:{
name: ‘lazy_tomato’,
age: 14
}但是 b栈内存中存储的地址也指向这个对象,所以 修改a,会同时修改b
浅拷贝
浅拷贝: 创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
看不懂定义?那就简单点说: 就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。
题目二,其实就是属于浅拷贝,修改了变量a,变量b也跟着改变。
浅拷贝实现方式
可以通过简单的赋值实现
类似上面的例子
利用 Object.assign()实现
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。
var obj = { a: { a: "hello", b: 21 } };var newObj = Object.assign({}, obj);console.log("obj变量为:", obj, "newObj: ", newObj)
//obj变量为: { a: { a: 'hello', b: 21 } } newObj: { a: { a: 'hello', b: 21 } }newObj.a.a = "lazy_tomato";console.log("obj变量为:", obj, "newObj: ", newObj)
//obj变量为: { a: { a: 'lazy_tomato', b: 21 } } newObj: { a: { a: 'lazy_tomato', b: 21 } }
注意:当object只有一层的时候,是深拷贝,例如如下:
var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = Object.assign({}, obj1);console.log(obj1, obj2);
//{ a: 10, b: 20, c: 30 } { a: 10, b: 20, c: 30 }obj1.b = 100;
console.log(obj1, obj2);
//{ a: 10, b: 100, c: 30 } { a: 10, b: 20, c: 30 }
深拷贝
- 深拷贝: 将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象
深拷贝实现方式
1、对象只有一层的话可以使用上面的:Object.assign()函数
2、转成 JSON 再转回来
var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj1, obj2) //{ body: { a: 10 } } { body: { a: 10 } }
obj1.body.a = 20;
console.log(obj1, obj2) //{ body: { a: 20 } } { body: { a: 10 } }
缺点
- 拷贝对象的值,如果存在函数、undefined、symbol,在经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失;
- 没办法拷贝不可枚举的属性,也不像for in 那样可以拷贝原型上的数据;
- 拷贝Date引用类型会变成字符串
- 拷贝RegExp 、Error 引用类型会变成 空对象
- 对象中含有NaN,Infinity和-Infinity,则序列化的结果会变成null
3、递归拷贝
- 写个函数实现递归拷贝
function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { var prop = initalObj[i]; if(prop === obj) { continue;} if (typeof prop === 'object') {obj[i] = (prop.constructor === Array) ? [] : {}; arguments.callee(prop, obj[i]);} else {obj[i] = prop;}} return obj;}
参考的相关网站博客
写的很好的个人博客
掘金的文章
END
- 写着写着,发现自己还有好多不懂的呀,o(╥﹏╥)o,挂出的相关博客都很棒,推荐看看。加油啦~~ 后续对js更加精通了,再来补充这篇文章。
- 个人记录,参考即可。
前端克隆数据 --JS 深浅拷贝相关推荐
- 【学姐面试宝典】前端基础篇Ⅴ——JS深浅拷贝、箭头函数、事件监听等
前言 博主主页
- 9012年,当我们讨论js深浅拷贝时我们在说些什么?
前言: 本文主要阅读对象:对深浅拷贝印象模糊对初级前端,想对js深浅拷贝聊一聊的中级前端.如果是对这些有完整对认知体系和解决方法的大佬,可以选择略过. 复制代码 正文: 讨论深浅拷贝,首先要从js的基 ...
- Mat数据的深浅拷贝
1.Mat数据的深浅拷贝 拷贝Mat时默认为浅拷贝,只拷贝Header中的内容,数据不变 Mat浅拷贝 Mat A A = imread(file, IMREAD_COLOR) Mat B(A); B ...
- 集合 小数据池 深浅拷贝
set 集合 列表.元组.字符串去重 集合中的元素必须是可哈希(hash)的,但set本身是不可哈希的可变的(有增删改查).不重复.无序的 创建一个空集合 s = set{} 1.关系型 ...
- 实现JS深浅拷贝的五种方式
一.堆栈.基本数据类型.引用数据类型 在了解深浅拷贝之前,我们需得对堆栈.基本数据类型.引用数据类型有基本的了解 基本数据类型:number.string.boolean.null.undefined ...
- JS中深浅拷贝 函数封装代码
一.了解 基本数据类型保存在栈内存中,按值访问,引用数据类型保存在堆内存中,按址访问. 二.浅拷贝 浅拷贝只是复制了指向某个对象的指针,而不是复制对象本身,新旧对象其实是同一内存地址的数据,修改其中一 ...
- php深浅拷贝,JavaScript 中的深浅拷贝
工作中经常会遇到需要复制 JavaScript 数据的时候,遇到 bug 时实在令人头疼:面试中也经常会被问到如何实现一个数据的深浅拷贝,但是你对其中的原理清晰吗?一起来看一下吧! 一.为什么会有深浅 ...
- Python的深浅拷贝讲解!
↑↑↑关注后"星标"Datawhale 每日干货 & 每月组队学习,不错过 Datawhale干货 作者:皮钱超,厦门大学,Datawhale原创作者 本文约3000字,建 ...
- 【Python基础】Python的深浅拷贝讲解
点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 前言 在很多语言中都存在深浅拷贝两种拷贝数据的方式,Python中 ...
- js之深浅克隆(深浅拷贝)
目录 1.浅克隆(浅拷贝) 2.深克隆(深拷贝) 总结 1.浅克隆(浅拷贝) 无法进行引用类型(地址和地址中数据的)双重拷贝,从而导致克隆者和被克隆者指向同一地址后,任何一方发生数据的改变都会影响对方 ...
最新文章
- qml学习笔记(二):可视化元素基类Item详解(上半场anchors等等)
- java jmx连接不上_JMX连接服务端失败
- 【转】HTML5 本地存储五种方案
- 数据库设计之从0到1 教你如何设计E-R图
- C++ 引用本质就是一个指针常量
- 苹果禁用FaceTime多人聊天功能:漏洞将很快修复
- mysql连接查询_.net core 里连接mysql查询数据的方法
- 手机端页面自适应解决方案—rem布局进阶版
- python local global_Python 变量作用域 LEGB (上)—— Local,Global,Builtin
- 考不上本科是智商问题,这话有错吗?
- proteus中ISIS软件的各种器件的添加
- C语言——指针详解(必收藏)
- Web前端笔记和简历模板
- Java 中的 IO 和 NIO
- kotlin android 开源,Kotlin开源项目集合
- 数据治理之数据质量管控流程(参考)
- ACER-4738ZG 拆机改散热
- Elasticsearch中object类型与nested类型之间的区别
- Java中的动态代理详解
- PLC通讯实现-C#实现西门子PLC以太网通讯Sharp7(六)
热门文章
- 基于Maven的SSM总体架构设计(四)
- django.db.utils.DataError: (1366, “Incorrect string value: ‘\\xE5\\x85\\xAD\\xE5\\x8D\\x83‘ for colu
- linux 系统找回密码,Linux系统密码忘记后的五种恢复方法
- 各行各业求职-招聘QQ群欢迎加入
- 南京商标注册流程是什么
- discuz template 模板文件说明
- 最受IT公司欢迎的30款开源软件
- 计算机连上wifi无法上网了,电脑已连接wifi但无法上网 已连接wifi但电脑无法上网-192路由网...
- 基于python+django框架+Mysql数据库的校园运动场地预约系设计与实现
- 4n35光耦引脚图_常见的高速光耦引脚图