js-深拷贝浅拷贝
深拷贝浅拷贝可以考察一个人的很多方面,例如:基本功,逻辑能力,编码能力;
在实际工作中的应用:比如用于页面展示的数据状态,与需要传给后端的数据包中,有部分字段的值不一致的话,就需要在传参时根据接口文档覆写那几个字段的值。最常见的可能就是 status 这个参数了。界面上的展示需要 Boolean 值,而后端同学希望拿到的是 Number 值,1 或者 0。为了不影响展示效果,往往就需要深拷贝一下,再进行覆写,否则界面上就会因为某些值的变化,出现奇怪的现象。
一、赋值
JavaScript原始数据类型:number,string,boolean,null,undefind,symbol他们的赋值很简单,且赋值后两个变量互不影响;
let test1 = 'JavaScript';
let test2 = test1;
// test2: JavaScript
test1 = 'JavaScript_change';
// test2: JavaScript
// test1: JavaScript_change
另外的引用数据类型:object和array,深拷贝和浅拷贝的出现就与这两个数据类型有关。
const obj={a:1,b:2};
const obj2=obj;
obj2.a=3;
console.log(obj.a);//
依照赋值的思路,对 Object 引用类型进行拷贝,就会出问题。很多情况下,这不是我们想要的。这时,就需要用浅拷贝来实现了。
二、浅拷贝
理解:创建一个新的对象,把原有的对象属性值,完整地拷贝过来。其中包括了原始类型的值,还有引用类型的内存地址。
const obj = {a:1, b:2};
const obj2 = Object.assign({}, obj);
obj2.a = 3;
console.log(obj.a); //
改变了obj2:a的属性,但是obj:a的属性没有发生改变;
可是这样的拷贝还有瑕疵:
const arr = [{a:1,b:2}, {a:3,b:4}];
const newArr = [].concat(arr);
newArr.length = 1; // 为了方便区分,只保留新数组的第一个元素
console.log(newArr); // [{a:1,b:2}]
console.log(arr); // [{a:1,b:2},{a:3,b:4}]
newArr[0].a = 123; // 修改 newArr 中第一个元素的a
console.log(arr[0]); // {a: 123, b: 2},竟然把 arr 的第一个元素的 a 也改了
对象的object.assign(),数组的 Array.prototype.slice() Array.prototype.concat(),还有 ES6 的 扩展运算符,都有类似的问题,它们都属于浅拷贝。这一点,在实际工作中处理数据的组装时,要格外注意。
所以浅拷贝可以这样理解:只拷贝第一层的原始类型值,和第一层的引用类型的地址。
三、深拷贝
我们希望当拷贝多层级的对象时也能实现互不影响的效果。所以,深拷贝的概念也就油然而生了。我们将深拷贝定义为:拷贝所有的属性值,以及属性地址指向的值的内存空间。
也就是说:当遇到对象时,就再新开一个对象,然后将第二层源对象的属性值,完整的拷贝到这个新开的对象中。
按照浅拷贝的思路,很容易就想到了递归调用。所以,就可以封装一个深拷贝的方法:
function deepClone(obj) {
if(!obj && typeof obj !== 'object'){
return;
}
var newObj= toString.call(obj) === '[object Array]' ? [] : {};
for (var key in obj) {
if (obj[key] && typeof obj[key] === 'object') {
newObj[key] = deepClone(obj[key]);
} else {
newObj[key] = obj[key];
}
}
return newObj;
}
结果:
let arr = [{a:1,b:2}, {a:3,b:4}];
let newArr = deepClone(arr);
newArr.length = 1; // 为了方便区分,只保留新数组的第一个元素
console.log(newArr); // [{a:1, b:2}]
console.log(arr); // [{a:1, b:2}, {a:3, b:4}]
newArr[0].a = 123; // 修改 newArr 中第一个元素的 a
console.log(arr[0]); // {a:1, b:2}
达到了想要的效果;
但是,这个方法貌似存在引用丢失问题,比如:
var b = {};
var a = {a1: b, a2: b};
a.a1 === a.a2 // true
var c = clone(a);
c.a1 === c.a2 // false
四、利用JSON解决深拷贝问题
let newArr2 = JSON.parse(JSON.stringify(arr));
console.log(arr[0]); // {a:1, b:2}
newArr2[0].a = 123;
console.log(arr[0]); // {a:1, b:2}
JOSN.parse()方法将JSON字符串转化为对象,JSON.stringify()方法将JavaScript字符串转化为对象。
但是,JSON 内部用了递归的方式,数据一但过多,就会有递归爆栈的风险。
五、lodash的_.clone和_.deepclone
const _ = require('lodash');//*
本质上的原因是对象引用的是地址,直接赋值会把引用地址也复制给新值。
浅复制只会将对象的各个属性进行依次复制,会把引用地址也复制。
深拷贝是会递归源数据,把新值的引用地址给换掉。
const _ = require('lodash')
var objects = [{ 'a': 1 }, { 'b': 2 }];
var shallow = _.clone(objects);
shallow[0].a = 333;
console.log(shallow,objects)//a=333,a=333
console.log(shallow[0] === objects[0])//true
const _ = require('lodash')
var objects = [{ 'a': 1 }, { 'b': 2 }];
var shallow = _.cloneDeep(objects);
shallow[0].a = 333;
console.log(shallow,objects)//a=333,a=1
console.log(shallow[0] === objects[0])//false
object.assign方法:
object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
object.assign方法的第一个参数是目标对象,剩下所有的参数都是源对象。
如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
如果只有一个参数该方法会直接返回该参数,若参数不是对象,则会先转成对象然后返回。
js-深拷贝浅拷贝的更多相关文章
- js 深拷贝和浅拷贝
js 深拷贝和浅拷贝 先举一下项目中遇到的两个例子: 例子1: var json = $.parseJSON(data.data);//data.data是接口返回的值var a = json.cha ...
- js对象浅拷贝和深拷贝详解
js对象浅拷贝和深拷贝详解 作者:i10630226 字体:[增加 减小] 类型:转载 时间:2016-09-05我要评论 这篇文章主要为大家详细介绍了JavaScript对象的浅拷贝和深拷贝代码,具 ...
- 老生常谈之js深拷贝与浅拷贝
前言 经常会在一些网站或博客看到"深克隆","浅克隆"这两个名词,其实这个很好理解,今天我们就在这里分析一下js深拷贝和浅拷贝. 浅拷贝 我们先以一个例子来说明 ...
- 关于JS深拷贝和浅拷贝
最近在前端开发中遇到一些问题,就是数组中的某个对象或某个对象的值改变之后,在不刷新页面的时候需要重新渲染值时,页面显示的还是原来的数据.比如: data{ A:[{id:1,num:1},{id:2, ...
- JS Object Deep Copy & 深拷贝 & 浅拷贝
JS Object Deep Copy & 深拷贝 & 浅拷贝 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Refe ...
- 理解JS深拷贝
前言: JS的拷贝(copy),之所以分为深浅两种形式,是因为JS变量的类型存在premitive(字面量)与reference(引用)两种区别.当然,大多数编程语言都存在这种特性. 众所周知,内存包 ...
- js深拷贝你还不会吗
js深拷贝 在讲正题之前我们要先了解数据存储的方式 数据存储方式 在讲之前我们要先知道值类型和引用类型的存储方式. 在JavaScript数据类型中有两种数据类型. 值类型:字符串(String).数 ...
- c# 内存的具体表现- 通用类型系统 深拷贝 浅拷贝 函数传参
c# 通用类型系统 及变量在 深拷贝 浅拷贝 函数传参 中的深层次的表现 在编程中遇到了一些想不到的异常,跟踪发现,自己对于c#变量在内存上的表现理解有偏差,系统的学习并通过代码实验梳理了各种情况下, ...
- python集合增删改查,深拷贝浅拷贝
集合 集合是无序的,不重复的数据集合,它里面的元素是可哈希的(不可变类型),但是集合本身是不可哈希(所以集合做不了字典的键)的.以下是集合最重要的两点: 去重,把一个列表变成集合,就自动去重了. 关系 ...
- JavaScript之深拷贝&浅拷贝
深拷贝&浅拷贝,说起来都明白,但是说不出所以然.今天就系统的整理下思绪,一点点的将其分析出所以然 废话不多说 浅拷贝 简单的说就是一个值引用,学生时代接触过编程的人都应该了解过指针,浅拷贝可以 ...
随机推荐
- 被 GANs 虐千百遍后,我总结出来的 10 条训练经验
一年前,我决定开始探索生成式对抗网络(GANs).自从我对深度学习产生兴趣以来,我就一直对它们很着迷,主要是因为深度学习能做到很多不可置信的事情.当我想到人工智能的时候,GAN是我脑海中最先出现的一个 ...
- 对于隐藏性质的非标准的动态 id 的下拉框,如何定位和选中
今天,在页面上碰到一个非 select 标签的下拉框,打算进行定位和模拟选中. <input aria-invalid="false" autocomplete=" ...
- c#_sort排序函数的返回值
C# List.Sort函数的返回值 值 含义 小于零 left在right的前面 零 位置不变 大于零 right在left的前面 示例: 本测试结果在unity3d 和纯C#环境下执行. List ...
- Java面试中遇到的坑【篇二面试干货】
俗话说早起的鸟儿有虫吃,现在临年关越来越近,有跳槽的想法的同事也都打算年前做好功课年后入职,所谓年终奖拿了,工作换的也是水到渠成. 说到这里想必有同学要说了,年底了放着年终奖不拿为何要跳槽呢?这个就要 ...
- 2019徐州网络赛 H.function
题意: 先有\(n=p_1^{k_1}p_2^{k_2}\cdots p_m^{k_m}\),定义\(f(n)=k_1+k_2+\cdots+k_m\). 现在计算 \[ \sum_{i=1}^nf( ...
- gyp --depth . -D component=shared_library -Ibuild/standalone.gypi build/all.gyp
gyp --depth . -D component=shared_library -Ibuild/standalone.gypi build/all.gyp
- MySQL学习笔记8——多表查询
多表查询 多表查询 *合并结果集 *连接查询 *子查询 合并结果集 *要求被合并的表中,列的类型和列数相同(实际上是查询的结果集列类型和列数相同即可) *UNION,去除重复行 *UNION ALL, ...
- CF1256A Payment Without Change
CF1256A Payment Without Change 洛谷评测传送门 题目描述 You have aa coins of value nn and bb coins of value 11 . ...
- LINUX下查看点云图————point cloud(.ply .vtk .pcd)
首先,你要确定点云的格式:.pcd(.vtk) 还是 .ply 如果是.pcd(.vtk),那么可以用pcl工具查看: 1.安装pcl,官网链接点击打开链接 sudo add-apt-reposito ...
- 安装Rtools
1.好多工具需要安装Rtools install.packages("installr") install.packages("stringr") ###依赖包 ...