javascript浅拷贝深拷贝理解记录
javascript的深拷贝和浅拷贝问题几乎是面试必问的问题。好记性不如烂笔头,特此来记录一下自己对深拷贝浅拷贝的理解。
顾名思义,拷贝就是copy复制,在js中可以浅而理解为对一个对象或者数组的复制。但是复制后的对象或者数组是否是和原来的对象指向同一个地址内存还是新开辟了一个地址内存,这就衍生出了javascript的深拷贝和浅拷贝的问题了;深复制和浅复制只针对像 Object, Array 这样的复杂对象的。简单来说,浅复制只复制一层对象的属性,而深复制则递归复制了所有层级。
一、javascript浅拷贝
浅拷贝:只复制一层对象属性,可以理解为,只复制对象的基本属性类型,而基本属性类型是存放在栈内存中的,可以直接修改访问的,所以当浅拷贝时,拷贝的对象只是拷贝了原对象的属性,而值都是指向同一个栈内存中的数据,当对象属性值发生修改时,原对象也会被修改。如下示例:
let arr1 = {
color:'red',
name:'apple',
weight:'100g',
detail:{
big:'true',
eating:'no'
}
};
let arr2;
arr2 = arr1;
arr2.color = 'black';
console.log(arr2);
console.warn(arr1);
输出值:
可以看到,当arr2的color发生变化时,被复制的对象arr1的color值也发生了变化。
但是在实际项目应用中,我们复制了某个对象之后绝大多数情况下都是不希望被复制的对象的值会发生变化,这里就涉及到javascript的深拷贝问题以及他的实现。
二、javascript深拷贝
深拷贝:它不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上。这就不会存在上面 obj 和 shallowObj 的 arr 属性指向同一个对象的问题。这是我从某官网看来的解释,我感觉挺绕的,结合对象来看,深拷贝存在于对象这种引用类型中,而引用类型的数据是存在堆内存上的,变量保存的是一个指针,这个指针指向另一个位置。当需要访问引用类型(如对象,数组等)的值时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。深拷贝可以看做是在堆内存中新开辟了一个内存空间,复制后的对象的属性所指的指针会指向新开辟的内存空间的地址。所以复制后的对象对属性值进行修改不会影响原对象的属性值。
那如何实现深拷贝呢?
1、通过JSON.parse(JSON.stringify(arr))接上面的例子:
let arr3 = JSON.parse(JSON.stringify(arr1));
arr3.color="balck";
console.log(arr3);
console.warn(arr1);
输出结果:
这个方法我觉得是最简洁的,但是它有一些弊端:
a、对于正则表达式类型、函数类型等无法进行深拷贝(而且会直接丢失相应的值)
b、深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object
c、如果对象中存在循环引用的情况也无法正确处理。
2、通过for循环递归调用
function deepClone(obj){
//判断obj是否是数组
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判断ojb子元素是否为对象,如果是,递归复制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
var arr4 = deepClone(arr1);
arr4.name='bananer';
console.log(arr4);
console.warn(arr1);
输出结果:
但是,这样的深拷贝进行的循环递归调用,如果对象数据量庞大显然会影响性能,所以一般在项目中很少使用,循环进行深拷贝,可以考虑其他方式来实现对象值的复制引用。
3、数组concat方法
let arr4 = [1,2,3]
let arr5 = [].concat(arr4)
arr5.push(4)
console.log(arr4, arr5, 'deep copy')
// [1,2,3] [1,2,3,4]
4、js扩展运算符(...)
let arr8 = [1,2,3]
let arr9 = [...arr8]
arr9.push(4)
console.log(arr8, arr9, 'deep copy 2')
// [1,2,3] [1,2,3,4]
javascript浅拷贝深拷贝理解记录的更多相关文章
- javascript浅拷贝深拷贝详解
一.浅拷贝 浅拷贝在现实中最常见的表现在赋值上面,例如 <!DOCTYPE html> <html lang="en"> <head> < ...
- 也来玩玩 javascript对象深拷贝,浅拷贝
经常看到讨论c#深拷贝,浅拷贝的博客,最近js写的比较多, 所以也来玩玩js的对象拷贝. 下面是维基百科对深浅拷贝的解释: 浅拷贝 One method of copying an object is ...
- javascript对象深拷贝,浅拷贝 ,支持数组
javascript对象深拷贝,浅拷贝 ,支持数组 经常看到讨论c#深拷贝,浅拷贝的博客,最近js写的比较多, 所以也来玩玩js的对象拷贝. 下面是维基百科对深浅拷贝的解释: 浅拷贝 One meth ...
- JavaScript之深拷贝&浅拷贝
深拷贝&浅拷贝,说起来都明白,但是说不出所以然.今天就系统的整理下思绪,一点点的将其分析出所以然 废话不多说 浅拷贝 简单的说就是一个值引用,学生时代接触过编程的人都应该了解过指针,浅拷贝可以 ...
- JavaScript的深拷贝和浅拷贝总结
深拷贝和浅拷贝 深拷贝:拷贝实例:浅拷贝:拷贝引用(原对象). 说深拷贝和浅拷贝之前,我先去了解了下高程书上的JavaScript的变量类型: 基本类型:undefined.null.Boolean. ...
- 【javascript】浅谈javaScript的深拷贝
前言: 最开始意识到深拷贝的重要性是在我使用redux的时候(react + redux), redux的机制要求在reducer中必须返回一个新的对象,而不能对原来的对象做改动,事实上,当时 ...
- $.extend()浅拷贝深拷贝
参考网址:http://bijian1013.iteye.com/blog/2255037 jQuery.extend() 函数用于将一个或多个对象的内容合并到目标对象. 注意:1. 如果只为$.ex ...
- 【javascript】详解javaScript的深拷贝
前言: 最开始意识到深拷贝的重要性是在我使用redux的时候(react + redux), redux的机制要求在reducer中必须返回一个新的对象,而不能对原来的对象做改动,事实上,当时 ...
- JavaScript实现深拷贝(深复制) 面试题
1.两种方法实现深拷贝(深复制) (1)方法一:兼容性好,请仔细看代码(网上大部分代码有Bug) (2)方法二:需要对象满足JSON数据格式.JOSN数据格式:http://www.cnblogs.c ...
随机推荐
- POJ 1300.Door Man 欧拉通路
Door Man Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 2596 Accepted: 1046 Descript ...
- Mockplus推出真正无限制终身版,做原型就要一辈子!
如今提到原型工具,各位设计师和PM爸爸们一定不会对Mockplus感到陌生吧?事实上,从一开始的默默无闻,到在UXPA大赛上崭露头角,再到被Adobe XD 列为主要竞品,如今,摩客君已经在全球范围内 ...
- 慢工出细活,Facebook点赞按钮设计中的门道
一年前,Facebook点赞按钮发布更新.一年后的今天,Facebook小小的点赞按钮因为Ted刚发布的一段演讲掀起波澜.设计一个像FB点赞按钮那么小的东西很难么?Ted中Margaret Gould ...
- div 自适应宽度
div 自适应宽度 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://w ...
- C语言点滴
static修饰的变量和函数不可以在其他文件extern引用该变量或者函数. static变量放在静态内存区. static变量赋值只生效一次,再无法调用赋值语句.但是可以运算,例如++等. exte ...
- Alien::BatToExeConverter 模块应用
## DOS 下批量任务转换成exe二进制可执行文件 Convert a DOS Batch Script to an Executable Alien::BatToExeConverter::ba ...
- 前端之css笔记1
1 css引入方式 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...
- yum 报错:centos yum (28, 'Connection time-out') Trying other mirror.
前言: 在使用yum安装 软件时,经常出现 centos yum (28, 'Connection time-out') Trying other mirror. 或下面的那样情况imeout on ...
- 动态链接库编程:非MFC DLL
设计一个DLL,内含一个函数计算a+b: DLL的组成 .h(头文件) 定义了DLL能够导出的函数.数据结构或类的声明,该文件的声明内容在.CPP文件中实现,而.CPP的源程序被封装到DLL文件中 . ...
- (小数化分数)小数化分数2 -- HDU --1717
链接: http://acm.hdu.edu.cn/showproblem.php?pid=1717 举例: 0.24333333…………=(243-24)/900=73/3000.9545454…… ...