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

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

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

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

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

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

这个时候只是把obj1中保存的指向对象{name:'obj.name'}的内存地址赋给了obj2,并不会再创建一个对象{name:'obj.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复制代码

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

下篇文章讲如何手动实现一个深拷贝,有兴趣的朋友欢迎关注

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

转载于:https://juejin.im/post/5c99f1e5f265da60f20702e7

你可能感兴趣的文章
5个产品经理必须掌握的,小程序裂变案例
查看>>
Android知识点复习(一)-Android系统架构
查看>>
calc(~,mac电脑set-cookies要域名和请求域名相同
查看>>
小葵花妈妈课堂开课了:《Handler Looper Message 浅析》
查看>>
浏览器和node的eventLoop的区别
查看>>
Android-动画-view 动画笔记
查看>>
爬虫调用百度翻译API
查看>>
80%的前端程序员都遇到的问题,你中招了吗?
查看>>
slider轮播插件的多种写法
查看>>
小米6.0以上系统怎么无需root激活Xposed框架的步骤
查看>>
【Spring】HttpMessageConverter的作用及替换
查看>>
android 关于 textview首行缩进 显示图片、文字问题
查看>>
YTKNetwork使用application json方式传递参数
查看>>
HTML5 小动画例子
查看>>
温故之.NET 任务并行
查看>>
React怎样从函数中辨别类
查看>>
js中split之正则运用(模式匹配)
查看>>
Nuxt使用cookies踩坑之设置axios的header
查看>>
UIView的setNeedsLayout, layoutIfNeeded 和 layoutSubviews
查看>>
二维码编解码 Java调用示例代码
查看>>