赋值、浅拷贝与深拷贝

简介: 赋值、浅拷贝与深拷贝

前面我们讲过,基本数据类型存放的栈中,引用数据类型存放在堆中,指向引用数据类型的变量保存在栈中,它保存着指向堆中对应引用数据类型的内存地址(对以上问题不了解的朋友可以查看之前的一篇文章《JavaScript之内存空间》),由此看如下代码:


let a = 'a';
let b = a;
let obj1 = {
  name:'obj1.name'
}
let obj2 = obj1;
复制代码


首先声明了变量a并赋值'a',然后声明b = a,这个时候属于赋值,即创建变量b,并赋值'a';


接下来声明对象obj1并赋值,此时在内存中创建了对象{name:'obj1.name'},然后声明obj2 = obj1,


这个时候只是把obj1中保存的指向对象{name:'obj1.name'}的内存地址赋给了obj2,并不会再创建一个对象{name:'obj1.name'}


那么接下来看如下代码:


let xm = {
  name:'小明',
  hobby:['足球','篮球']
}
let xz = xm;
console.log(xm);
// {
//   name:'小明',
//   hobby:['足球','篮球']
// }
console.log(xz);
// {
//   name:'小明',
//   hobby:['足球','篮球']
// }
xz.name = '小张';
console.log(xm);
// {
//   name:'小张',
//   hobby:['足球','篮球']
// }
console.log(xz);
// {
//   name:'小张',
//   hobby:['足球','篮球']
// }
复制代码


因为let xz = xm只是把xm保存的对象的内存地址赋给了xz,所以当通过xz.name = '小张'改变了这个对象的时候,打印xm和xz拿到的都是改变后的对象,那么如何复制一个对象呢?


可能你会想到Object.assign()


**Object.assign()** 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。  ---- (MDN)


那我们修改上面的代码如下:


let xm = {
  name:'小明',
  hobby:['足球','篮球']
}
let xz = Object.assign({},xm);
console.log(xm);
// {
//   name:'小明',
//   hobby:['足球','篮球']
// }
console.log(xz);
// {
//   name:'小明',
//   hobby:['足球','篮球']
// }
xz.name = '小张';
console.log(xm);
// {
//   name:'小明',
//   hobby:['足球','篮球']
// }
console.log(xz);
// {
//   name:'小张',
//   hobby:['足球','篮球']
// }
复制代码


可能你会觉得还不错嘛,那我们再修改一下:


let xm = {
  name:'小明',
  hobby:['足球','篮球']
}
let xz = Object.assign({},xm);
console.log(xm);
// {
//   name:'小明',
//   hobby:['足球','篮球']
// }
console.log(xz);
// {
//   name:'小明',
//   hobby:['足球','篮球']
// }
xz.name = '小张';
xz.hobby.push('乒乓球');
console.log(xm);
// {
//   name:'小明',
//   hobby:['足球','篮球','乒乓球']
// }
console.log(xz);
// {
//   name:'小张',
//   hobby:['足球','篮球','乒乓球']
// }
复制代码


你会发现,不对啊,我明明只想给xz添加爱好,xm的爱好怎么也多了?


下面我们正式引出浅拷贝和深拷贝


浅拷贝


其实浅拷贝就像我们上面说的变量赋值,当对象的属性值为基本数据类型,那么拷贝的就是基本数据类型的值,如果对象的属性值为引用数据类型,那么拷贝的就是内存地址,上面的代码可以用下图更形象的解释:


网络异常,图片无法展示
|


所以,类似于Object.assign()属于浅拷贝


深拷贝


理解了浅拷贝,深拷贝的概念就呼之欲出了,所谓深拷贝,即不管对象的属性是基本数据类型还是引用数据类型,都会进行拷贝,所以拷贝前后的两个对象是相互独立,互不影响的。


上面例子实现深拷贝代码如下:


let xm = {
  name:'小明',
  hobby:['足球','篮球']
}
let xz = JSON.parse(JSON.stringify(xm));
xz.name = '小张';
xz.hobby.push('乒乓球');
console.log(xm);
// {
//   name:'小明',
//   hobby:['足球','篮球']
// }
console.log(xz);
// {
//   name:'小张',
//   hobby:['足球','篮球','乒乓球']
// }
复制代码


JSON.parse(JSON.stringify(obj))存在以下几个问题:


let obj1 = {
  name:'obj',
  a:undefined,
  b:/\d{6}/g,
  c:function(){
    console.log(this)
  },
  d:new Date(),
  s:Symbol(123)
}
let obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj2);
// {
//   name: "obj",
//   b: {},
//   d: "2019-03-26T13:51:45.158Z"
// }
复制代码


可见对于undefined,函数,Symbol会直接忽略


对于new Date()转换后结果不正确


对于正则转换为{}


再看一种情况:


let obj1 = {
  a:{name:'a'}
}
obj1.b = obj1.a;
obj1.b.c = obj1.a;
console.log(obj1);
let obj2 = (JSON.parse(JSON.stringify(obj1)));
console.log(obj2);
// Uncaught TypeError: Converting circular structure to JSON
复制代码


可见对于循环引用,会报错。


如果有错误或者不严谨的地方,请给予指正,十分感谢!


相关文章
|
9月前
|
JSON Java API
深拷贝、浅拷贝
深拷贝、浅拷贝
21 0
|
9月前
|
JavaScript 前端开发 Python
故事会【深拷贝和浅拷贝】
故事会【深拷贝和浅拷贝】
|
7天前
|
安全 Java
深拷贝和浅拷贝的区别
深拷贝和浅拷贝的区别
|
2月前
|
消息中间件 Kubernetes NoSQL
构造函数、深拷贝、浅拷贝
构造函数、深拷贝、浅拷贝
|
12月前
|
前端开发
对于深拷贝与浅拷贝的理解
对于深拷贝与浅拷贝的理解
|
12月前
深拷贝和浅拷贝
类里面会为我们实现默认的拷贝,这个做的是值的拷贝,但是假如对象里的数据成员在堆上开辟了内存资源,如果继续浅拷贝就会导致两根指针指向同一块资源,从而产生内存泄漏问题。但是深拷贝可以解决这个问题,本文将详细介绍深拷贝与浅拷贝。
|
JSON JavaScript 数据格式
js对象的直接赋值、浅拷贝与深拷贝
js对象的直接赋值、浅拷贝与深拷贝
131 0
js对象的直接赋值、浅拷贝与深拷贝
|
JavaScript 前端开发
数组和对象的浅拷贝,深拷贝
数组和对象的浅拷贝,深拷贝
数组和对象的浅拷贝,深拷贝
|
编译器 C++
C++拷贝构造函数(深拷贝,浅拷贝)详解
C++拷贝构造函数(深拷贝,浅拷贝)详解
C++拷贝构造函数(深拷贝,浅拷贝)详解