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浅拷贝深拷贝理解记录的更多相关文章

  1. javascript浅拷贝深拷贝详解

    一.浅拷贝 浅拷贝在现实中最常见的表现在赋值上面,例如 <!DOCTYPE html> <html lang="en"> <head> < ...

  2. 也来玩玩 javascript对象深拷贝,浅拷贝

    经常看到讨论c#深拷贝,浅拷贝的博客,最近js写的比较多, 所以也来玩玩js的对象拷贝. 下面是维基百科对深浅拷贝的解释: 浅拷贝 One method of copying an object is ...

  3. javascript对象深拷贝,浅拷贝 ,支持数组

    javascript对象深拷贝,浅拷贝 ,支持数组 经常看到讨论c#深拷贝,浅拷贝的博客,最近js写的比较多, 所以也来玩玩js的对象拷贝. 下面是维基百科对深浅拷贝的解释: 浅拷贝 One meth ...

  4. JavaScript之深拷贝&浅拷贝

    深拷贝&浅拷贝,说起来都明白,但是说不出所以然.今天就系统的整理下思绪,一点点的将其分析出所以然 废话不多说 浅拷贝 简单的说就是一个值引用,学生时代接触过编程的人都应该了解过指针,浅拷贝可以 ...

  5. JavaScript的深拷贝和浅拷贝总结

    深拷贝和浅拷贝 深拷贝:拷贝实例:浅拷贝:拷贝引用(原对象). 说深拷贝和浅拷贝之前,我先去了解了下高程书上的JavaScript的变量类型: 基本类型:undefined.null.Boolean. ...

  6. 【javascript】浅谈javaScript的深拷贝

        前言: 最开始意识到深拷贝的重要性是在我使用redux的时候(react + redux), redux的机制要求在reducer中必须返回一个新的对象,而不能对原来的对象做改动,事实上,当时 ...

  7. $.extend()浅拷贝深拷贝

    参考网址:http://bijian1013.iteye.com/blog/2255037 jQuery.extend() 函数用于将一个或多个对象的内容合并到目标对象. 注意:1. 如果只为$.ex ...

  8. 【javascript】详解javaScript的深拷贝

        前言: 最开始意识到深拷贝的重要性是在我使用redux的时候(react + redux), redux的机制要求在reducer中必须返回一个新的对象,而不能对原来的对象做改动,事实上,当时 ...

  9. JavaScript实现深拷贝(深复制) 面试题

    1.两种方法实现深拷贝(深复制) (1)方法一:兼容性好,请仔细看代码(网上大部分代码有Bug) (2)方法二:需要对象满足JSON数据格式.JOSN数据格式:http://www.cnblogs.c ...

随机推荐

  1. Java数据结构和算法(一)线性结构之单链表

    Java数据结构和算法(一)线性结构之单链表 prev current next -------------- -------------- -------------- | value | next ...

  2. 16款值得一用的iPhone线框图模板 (PSD & Sketch)

    在任何网站或移动应用设计的过程中,线框图作为设计元素和功能的图示,它有助于帮助定义和更好地传达信息层次结构,让参与设计和开发的人员更好的理解设计师的思路和设计的功能点. 即使线框图设计是一个比较耗时的 ...

  3. 8.13Oracle新建用户、角色,授权

    oracle数据库的权限系统分为系统权限与对象权限.系统权限( database system privilege )可以让用户执行特定的命令集.例如,create table权限允许用户创建表,gr ...

  4. jquery panel加载(dialog加载类似)

    项目情况: 主页面用引用了公共头文件(包含easui.min.js),使用easyui的dialog(href方式)打开窗口(被打开的窗口页面是纯html片段,无body元素等,也引入了公共头文件), ...

  5. 2018.07.06 POJ1273 Drainage Ditches(最大流)

    Drainage Ditches Time Limit: 1000MS Memory Limit: 10000K Description Every time it rains on Farmer J ...

  6. phonegap android插件,启动activity并返回值

    Your execute menthod is not quite right. When you do: return new PluginResult(PluginResult.Status.OK ...

  7. spring的IOC/DI功能实践

    一.写在前面: 做这个Demo主要是为了能够更好的理解Spring的原理,看再多的文章,听再多的讲解最终都最好自己去实现一遍,可以将Spring的功能分块实现,最终自然比较容易将各个功能组合起来. 这 ...

  8. 常用的SLAM解决方案

    ORB SLAM 可以去Github上自己搜索现成的SLAM程序包 在此基础上做优化 视觉SLAM的分类方法:按摄像头的多少分为单目和双目,按是否使用概率方法分为概率法和图法 链接 学习SLAM重要的 ...

  9. day14(xml 编写及解析)

    编写 xml的组成: 1.文档的声明 <?xml version='1.0' encoding='UTF-8' standalone='yes'> xml 表示标签的名字 encoding ...

  10. MFC中添加新的对话框

    MFC工程中,除了系统自动生成的一些对话框之外,还需要根据自己的需求,添加新的对话框.这里总结下自己最近使用的方法. 首先,找到Resource View中自己新建的工程,然后右键,选择Add Cla ...