博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深拷贝 vs 浅拷贝
阅读量:6084 次
发布时间:2019-06-20

本文共 2530 字,大约阅读时间需要 8 分钟。

深拷贝 vs 浅拷贝

深拷贝和浅拷贝都是针对的引用类型,JS中的变量类型分为值类型(基本类型)和引用类型;对值类型进行复制操作会对进行一份拷贝,而对引用类型赋值,则会进行地址的拷贝,最终两个变量指向同一份数据。

// 基本类型var a = 1;var b = a;a = 2;console.log(a, b); // 2, 1 ,a b指向不同的数据// 引用类型指向同一份数据var a = {c: 1};var b = a;a.c = 2;console.log(a.c, b.c); // 2, 2 全是2,a b指向同一份数据

对于引用类型,会导致a b指向同一份数据,此时如果对其中一个进行修改,就会影响到另外一个,有时候这可能不是我们想要的结果,如果对这种现象不清楚的话,还可能造成不必要的bug。那么如何切断a和b之间的关系呢,可以拷贝一份a的数据,根据拷贝的层级不同可以分为浅拷贝和深拷贝,浅拷贝就是只进行一层拷贝,深拷贝就是无限层级拷贝。

深复制和浅复制最根本的区别在于是否是真正获取了一个对象的复制实体,而不是引用

  • 深复制在计算机中开辟了一块内存地址用于存放复制的对象,
  • 浅复制仅仅是指向被复制的内存地址,如果原地址中对象被改变了,那么浅复制出来的对象也会相应改变。
var a1 = {b: {c: {}};var a2 = shallowClone(a1); // 浅拷贝a2.b.c === a1.b.c // truevar a3 = clone(a1); // 深拷贝a3.b.c === a1.b.c // false
所谓的浅复制,只是拷贝了基本类型的数据,而引用类型数据,复制后也是会发生引用,我们把这种拷贝叫做“(浅复制)浅拷贝”。Object.assign({}, obj1, obj2)
浅拷贝的实现
function shallowClone(source) {    var target = {};    for(var i in source) {        if (source.hasOwnProperty(i)) {            target[i] = source[i];        }    }    return target;}
深拷贝的实现

深拷贝的问题其实可以分解成两个问题,浅拷贝+递归,什么意思呢?假设我们有如下数据

var a1 = {b: {c: {d: 1}};

只需稍加改动上面浅拷贝的代码即可,注意区别

function clone(source) {    var target = {};    for(var i in source) {        if (source.hasOwnProperty(i)) {            if (typeof source[i] === 'object') {                target[i] = clone(source[i]); // 注意这里            } else {                target[i] = source[i];            }        }    }    return target;}

其实上面的代码问题太多了,先来举几个例子吧

  • 没有对参数做检验
function isObject(x) {    return Object.prototype.toString.call(x) === '[object Object]';}function clone(source) {    if (!isObject(source)) return source;    // xxx}
  • 判断是否对象的逻辑不够严谨
  • 没有考虑数组的兼容
  • 递归方法最大的问题在于爆栈,当数据的层次很深是就会栈溢出

方法: 用系统自带的JSON来做深拷贝的例子,下面来看下代码实现

function cloneJSON(source) {    return JSON.parse(JSON.stringify(source));}

但是cloneJSON也有缺点,它的内部也是使用递归的方式

cloneJSON(createData(10000)); // Maximum call stack size exceeded

既然是用了递归,那循环引用呢?并没有因为死循环而导致栈溢出啊,原来是JSON.stringify内部做了循环引用的检测,正是我们上面提到破解循环引用的第一种方法:循环检测

var a = {};a.a = a;cloneJSON(a) // Uncaught TypeError: Converting circular structure to JSON

如何复制对象而不发生引用呢,对于数组,ES6我们复制有新的两种方法,不会发生引用。

第一种:Array.from(要复制的数组);

var arr1=[1,2,3];var arr2=Array.from(arr1);arr1.push(4);alert(arr1);  //1234alert(arr2);  //123arr2.push(5);alert(arr1);  //1234alert(arr2);  //1235

第二种:...

var arr1=[1,2,3];var arr2=[...arr1];arr1.push(4);alert(arr1);  //1234alert(arr2);  //123arr2.push(5);alert(arr1);  //1234alert(arr2);  //1235

第二种这个方法也可以用在函数的行参上面。

function show(...arr1){  //直接来复制arguments这个伪数组,让它变成真正的数组,从而拥有数组的方法。  alert(arr1); //1234  arr1.push(5);  alert(arr1); //12345}show(1,2,3,4)

转载地址:http://jmkwa.baihongyu.com/

你可能感兴趣的文章
tp框架之增删改查
查看>>
TextView改变颜色
查看>>
Android 项目中文件夹作用(res文件夹详细介绍)
查看>>
VC++排序 排序算法比较
查看>>
android studio本地gradle
查看>>
comet 推送消息到客户端
查看>>
Linux下一个进程可以开多少线程
查看>>
小错误汇总
查看>>
docker容器的两类存储
查看>>
从Controller到View(一)
查看>>
关于&、双引号、和单引号的解释
查看>>
LeetCode - Nth Digit
查看>>
background-clip&background-origin
查看>>
js读书笔记(2)
查看>>
修改表数据
查看>>
Web应用的目录结构
查看>>
jdk安装
查看>>
sendToTarget与sendMessage
查看>>
Datastage里Aggregator的一些注意事项
查看>>
验证String、StringBuffer、StringBuilder区别
查看>>