js 浅拷贝直接赋值_浅析JavaScript解析赋值、浅拷贝和深拷贝的区别

一、赋值(Copy)

赋值是将某一数值或对象赋给某个变量的过程,分为:

1、基本数据类型:赋值,赋值之后两个变量互不影响

2、引用数据类型:赋**址**,两个变量具有相同的引用,指向同一个对象,相互之间有影响

对基本类型进行赋值操作,两个变量互不影响。

// saucxs

let a = "saucxs";

let b = a;

console.log(b); // saucxs

a = "change";

console.log(a); // change

console.log(b); // saucxs

对引用类型进行赋**址**操作,两个变量指向同一个对象,改变变量 a 之后会影响变量 b,哪怕改变的只是对象 a 中的基本类型数据。

// saucxs

let a = {

name: "saucxs",

book: {

title: "You Don't Know JS",

price: "45"

}

}

let b = a;

console.log(b);

// {

// name: "saucxs",

// book: {title: "You Don't Know JS", price: "45"}

// }

a.name = "change";

a.book.price = "55";

console.log(a);

// {

// name: "change",

// book: {title: "You Don't Know JS", price: "55"}

// }

console.log(b);

// {

// name: "change",

// book: {title: "You Don't Know JS", price: "55"}

// }

通常在开发中并不希望改变变量 a 之后会影响到变量 b,这时就需要用到浅拷贝和深拷贝。

二、浅拷贝(Shallow Copy)

1、什么是浅拷贝

创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

上图中,`SourceObject` 是原对象,其中包含基本类型属性 `field1` 和引用类型属性 `refObj`。浅拷贝之后基本类型数据 `field2` 和 `filed1` 是不同属性,互不影响。但引用类型 `refObj` 仍然是同一个,改变之后会对另一个对象产生影响。

简单来说可以理解为浅拷贝只解决了第一层的问题,拷贝第一层的**基本类型值**,以及第一层的**引用类型地址**。

2、浅拷贝使用场景

2.1 Object.assign()

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

有些文章说`Object.assign()` 是深拷贝,其实这是不正确的。

// saucxs

let a = {

name: "saucxs",

book: {

title: "You Don't Know JS",

price: "45"

}

}

let b = Object.assign({}, a);

console.log(b);

// {

// name: "saucxs",

// book: {title: "You Don't Know JS", price: "45"}

// }

a.name = "change";

a.book.price = "55";

console.log(a);

// {

// name: "change",

// book: {title: "You Don't Know JS", price: "55"}

// }

console.log(b);

// {

// name: "saucxs",

// book: {title: "You Don't Know JS", price: "55"}

// }

上面代码改变对象 a 之后,对象 b 的基本属性保持不变。但是当改变对象 a 中的对象 `book` 时,对象 b 相应的位置也发生了变化。

2.2 展开语法 `Spread`

// saucxs

let a = {

name: "saucxs",

book: {

title: "You Don't Know JS",

price: "45"

}

}

let b = {...a};

console.log(b);

// {

// name: "saucxs",

// book: {title: "You Don't Know JS", price: "45"}

// }

a.name = "change";

a.book.price = "55";

console.log(a);

// {

// name: "change",

// book: {title: "You Don't Know JS", price: "55"}

// }

console.log(b);

// {

// name: "saucxs",

// book: {title: "You Don't Know JS", price: "55"}

// }

2.3 Array.prototype.slice方法

slice不会改变原数组,`slice()` 方法返回一个新的数组对象,这一对象是一个由 `begin`和 `end`(不包括`end`)决定的原数组的**浅拷贝**。

// saucxs

let a = [0, "1", [2, 3]];

let b = a.slice(1);

console.log(b);

// ["1", [2, 3]]

a[1] = "99";

a[2][0] = 4;

console.log(a);

// [0, "99", [4, 3]]

console.log(b);

// ["1", [4, 3]]

可以看出,改变 `a[1]` 之后 `b[0]` 的值并没有发生变化,但改变 `a[2][0]` 之后,相应的 `b[1][0]` 的值也发生变化。

说明 `slice()` 方法是浅拷贝,相应的还有`concat`等,在工作中面对复杂数组结构要额外注意。

三、深拷贝(Deep Copy)

3.1 什么是深拷贝?

深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。拷贝前后两个对象互不影响。

3.2 使用深拷贝的场景

3.2.1 JSON.parse(JSON.stringify(object))

// saucxs

let a = {

name: "saucxs",

book: {

title: "You Don't Know JS",

price: "45"

}

}

let b = JSON.parse(JSON.stringify(a));

console.log(b);

// {

// name: "saucxs",

// book: {title: "You Don't Know JS", price: "45"}

// }

a.name = "change";

a.book.price = "55";

console.log(a);

// {

// name: "change",

// book: {title: "You Don't Know JS", price: "55"}

// }

console.log(b);

// {

// name: "saucxs",

// book: {title: "You Don't Know JS", price: "45"}

// }

完全改变变量 a 之后对 b 没有任何影响,这就是深拷贝的魔力。

我们看下对数组深拷贝效果如何。

// saucxs

let a = [0, "1", [2, 3]];

let b = JSON.parse(JSON.stringify( a.slice(1) ));

console.log(b);

// ["1", [2, 3]]

a[1] = "99";

a[2][0] = 4;

console.log(a);

// [0, "99", [4, 3]]

console.log(b);

// ["1", [2, 3]]

对数组深拷贝之后,改变原数组不会影响到拷贝之后的数组。

但是该方法有以下几个问题:

(1)会忽略 `undefined`

(2)会忽略 `symbol`

(3)不能序列化函数

(4)不能解决循环引用的对象

(5)不能正确处理`new Date()`

(6)不能处理正则

其中(1)(2)(3) `undefined`、`symbol` 和函数这三种情况,会直接忽略。

// saucxs

let obj = {

name: 'saucxs',

a: undefined,

b: Symbol('saucxs'),

c: function() {}

}

console.log(obj);

// {

// name: "saucxs",

// a: undefined,

// b: Symbol(saucxs),

// c: ƒ ()

// }

let b = JSON.parse(JSON.stringify(obj));

console.log(b);

// {name: "saucxs"}

其中(4)循环引用会报错

// saucxs

let obj = {

a: 1,

b: {

c: 2,

d: 3

}

}

obj.a = obj.b;

obj.b.c = obj.a;

let b = JSON.parse(JSON.stringify(obj));

// Uncaught TypeError: Converting circular structure to JSON

其中(5)* `new Date` 情况下,转换结果不正确。

// saucxs

new Date();

// Mon Dec 24 2018 10:59:14 GMT+0800 (China Standard Time)

JSON.stringify(new Date());

// ""2018-12-24T02:59:25.776Z""

JSON.parse(JSON.stringify(new Date()));

// "2018-12-24T02:59:41.523Z"

解决方法转成字符串或者时间戳就好了。

// saucxs

let date = (new Date()).valueOf();

// 1545620645915

JSON.stringify(date);

// "1545620673267"

JSON.parse(JSON.stringify(date));

// 1545620658688

其中(6)正则情况下

// saucxs

let obj = {

name: "saucxs",

a: /'123'/

}

console.log(obj);

// {name: "saucxs", a: /'123'/}

let b = JSON.parse(JSON.stringify(obj));

console.log(b);

// {name: "saucxs", a: {}}

PS:为什么会存在这些问题可以学习一下 JSON。

除了上面介绍的深拷贝方法,

常用的还有`jQuery.extend()` 和 `lodash.cloneDeep()`,后面文章会详细介绍源码实现。

四、总结

和原数据是否指向同一对象

第一层数据为基本数据类型

原数据中包含子对象

赋值

改变会使原数据一起改变

改变会使原数据一起改变

浅拷贝

改变不会使原数据一起改变

改变会使原数据一起改变

深拷贝

改变不会使原数据一起改变

改变不会使原数据一起改变

五、参考

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/302068.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

限时秒杀│中科院推荐!6个引自美国NASA盒子,玩转科学

比勤奋更重要的,是孩子的思维能力。从上幼儿园开始,很多父母很喜欢给孩子报各种兴趣班,比如钢琴班、英语班、乐高班、报各种各样的课程,就是希望孩子具有18般武艺,赢在起跑线上。其实除了外在的能力,不显山…

html语言可以写模版继承吗,Django框架(十一):模板介绍、模板语言、模板继承、HTML转义...

1. 模板介绍1.1 模板的功能产生html,控制页面上展示的内容。模板文件不仅仅是一个html文件。模板文件包含两部分内容:静态内容:css、js、html。动态内容:用于动态去产生一些页面内容。通过模板语言来产生。1.2 模板文件的使用通常…

sed-笔记

一.sed脚本编程的方法论 1. 在着手做之前要弄清楚想做什么。2. 明确地描述处理的过程。3. 在提交最终的改变之前反复测试这个过程。注1:检测脚本最好的方式,是使用不同的输入样本进行测试并观察结果。二.…

.NET6又出新版本,新增这几个大杀器!

.NET6 Preview4终于发布了,作为第4个预览版,伴随着Build2021发布的,器更新内容也是非常丰富的。推荐关注的有以下11项:引入最小 API异步流HTTP 日志中间件新项目中使用 Kestrel 作为默认启动IConnectionSocketFeature改进单页应用…

蜗杆参数法设计_技术贴 | 减速器结构及设计的注意事项

减速机器用于低转速大扭矩的传动设备,原理是把电动机、内燃机、马达或其它高速运转的动力,通过减速机的输入轴上齿数少的齿轮啮合输出轴上的大齿轮,从而达到减速的目的;大小齿轮的齿数之比,就是传动比。减速器是一种由…

听说热爱生活的人都关注了他们

全世界有3.14 % 的人已经关注了数据与算法之美在信息爆炸的时代快节奏的生活里 你是否曾有一瞬间觉得忙碌而空虚?以下10个优质公众号能让你在闲暇的时候不断的提升自我,拓宽视野愿以书卷气,行我路千里近现代史研究通讯ID:jxsdyjtx…

基于abp vnext制作项目脚手架

首先说明,尊重原创,本文是参考https://www.cnblogs.com/myshowtime/p/14507675.html这篇文章写的,里面内容有部分是直接拷贝过来的。感谢作者分享!!!前期准备工作使用命令 abp new LS.Template --template …

Windows Server 2012 DHCP 服务器中的新功能:故障转移和策略

Windows Server 2012 DHCP 服务器中的新功能如下: DHCP 故障转移:此功能提供让两个 DHCP 服务器服务于 同一子网或作用域的 IP 地址和选项配置的能力,前提是 DHCP 服务对客户端持续可用。两个 DHCP 服务器复制它们之间的租用信息,…

android mvc mvp 简书,浅析 MVP,MVC,MVVM模式(Android)

前言当我们接手一个项目的时候,经常会发现一个activity或fragment动辄上千行甚至上万行代码,这给阅读带来很大的困扰,如果想读懂代码,需要花费很多时间跟精力。引起这个问题的原因想必大家都了解,随着人员不断变动&…

android studio插入数据表中没有_学Java能拿高薪吗 Java中常见排序算法有哪些

学Java能拿高薪吗?Java中常见排序算法有哪些?作为老牌编程语言,Java拥有广阔的市场占有率,几乎90%以上的大中型互联网应用系统在服务端开发都会首选Java。为了加入到Java这一高薪行业,很多人会选择专业学习一下&#x…

最全知识点总结!| 大数据学习路线指南

全世界只有3.14 % 的人关注了数据与算法之美大数据是对海量数据进行存储、计算、统计、分析处理的一系列处理手段,处理的数据量通常是TB级,甚至是PB或EB级的数据,这是传统数据处理手段所无法完成的,其涉及的技术有分布式计算、高并…

数组 边界 检查的几种实现方法

检查传递给函数的数组边界常用方法1.传递指向数组第一个和最后一个元素的下一个位置的指针。2. 将第二个形参定义为表示数组的大小3.数组本身放置一个检测位三种实现方法&#xff1a;#include<iostream> using namespace std; int sumArray(const int *beg,const int *e…

欢迎来到开源的世界!

✉️ 请查收您的保姆级开源百科编程导航 致力于推荐优质编程资源 ????项目开源仓库&#xff1a;https://github.com/liyupi/code-nav跪求一个 star ⭐️大家好&#xff0c;我是鱼二&#xff0c;今天推荐一份开源知识入门的在线电子书《开源指北》。正如官方对这本书的描述&…

html图片宽度高度等比例绽放,css图片自动绽放大小,左右,上下居中

无标题页.pic{max-height:400px;max-width:400px;_width:expression("400px");_height:expression((document.documentElement.clientHeight||document.body.clientHeight)>400?"400px":"");/*_width:expression((document.documentElement.…

归纳推理测试没做完_朋友买了1斤紫菜,2年还没吃完,我教他这样做,2个月就吃完了...

朋友买了1斤紫菜&#xff0c;2年还没吃完&#xff0c;我教他这样做&#xff0c;2个月就吃完了紫菜成熟啦&#xff0c;这段时间回老家&#xff0c;都会看到紫菜养殖户脸上挂着笑容&#xff0c;因为今年的紫菜收成还不错。回家就为了拿紫菜&#xff0c;因为紫菜成熟的季节&#x…

机器学习都需要有哪些数学知识?

随着科技的快速发展&#xff0c;人工智能的重要性日渐显现。机器学习是一个异常丰富的研究领域&#xff0c;有大量未解决的问题&#xff1a;公正、可解释性、易用性。如同所有的学科一样&#xff0c;它的基本思想不是请求式的过程&#xff0c;而是需要耐心地用高级数学框架思考…

(转)64bit上安装32位oracle 10 g出现错误:无法定位承诺工序输入点 getprocessimagifilenamew 于动态链接库PSAPI.DLL...

转自http://jonelove00.iteye.com/blog/1685206安装时以最高管理员身份运行&#xff1a;红色字体为自己加上去的代码找到..\database\stage\prereq\db\refhost.xml打开加入<OPERATING_SYSTEM> <VERSION VALUE"6.1"/></OPERATING_SYSTEM> 再找…

10kv电压互感器型号_电压互感器型号大全

电压互感器简介电压互感器(Potentialtransformer简称PT&#xff0c;Voltagetransformer也简称VT)和变压器类似&#xff0c;是用来变换线路上的电压的仪器。但是变压器变换电压的目的是为了输送电能&#xff0c;因此容量很大&#xff0c;一般都是以千伏安或兆伏安为计算单位&…

C# 常用接口学习 IEnumerableT

我们先去看看公开的.Net4.0的源程序中IEnumerable<T>、IEnumerable、IEnumerator<T>和IEnumerator这四个接口是如何声明的&#xff1a;需加微信交流群的&#xff0c;请加小编微信号zls20210502&#xff0c;切记备注 加群&#xff0c;小编将会第一时间邀请你进群&am…

html5伸缩效果,【HTML5】Jquery打造竖向伸缩/展开菜单

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼效果图如下&#xff1a;jquery打造竖向伸缩/展开菜单body { font-family: Arial; font-size: 16px; }dl { width: 300px; }dl,dd { margin: 0; }dt { background-color:#ae8758; background-image:url(/jscss/demoimg/201207.png);…