concat是深拷贝还是浅拷贝(解构赋值是深拷贝还是浅拷贝)
本文目录
解构赋值是深拷贝还是浅拷贝
深拷贝:修改新变量的值不会影响原有变量的值。默认情况下基本数据类型都是深拷贝。 浅拷贝:修改新变量的值会影响原有的变量的值。默认情况下引用类型都是浅拷贝。 ES6的新特性,按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为 解构 。具体操作本文章不做描述。 那么我们在使用解构赋值的时候,到底是深拷贝还是浅拷贝呢?我们可以通过以下的例子得出结论: 输出 以上例子中,我们从对象a中解构赋值了name、age、marriage、addr四个变量,分别是 string 、 number 、 boolean 、 object 类型。改变这四个变量的值后,再与a原来的值作对比,我们发现a的name,age,marriage属性没有改变,而addr属性发生了改变。由此可以得出结论,解构赋值对object类型只是浅拷贝。 实际上,无论是使用扩展运算符(...)还是解构赋值,对于引用类型都是浅拷贝。所以在使用splice()、concat()、...对数组拷贝时,只有当数组内部属性值不是引用类型是,才能实现深拷贝。
JSON对象实现深度克隆
JSON 是 ecma5新定义的对象,你要在 现代浏览器中才能有,如果你用ie6这样的浏览器就找不到,这个是先检查有没有JSON这个对象有的话就用这个对象深拷贝,没有的话自己实现,你这个自己实现的方法,不是深度拷贝,而是浅拷贝
彻底讲明白浅拷贝与深拷贝
数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型。
1、基本数据类型的特点:直接存储在栈(stack)中的数据
2、引用数据类型的特点: 存储的是该对象在栈中引用,真实的数据存放在堆内存里
引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的 。
深拷贝和浅拷贝的示意图大致如下:
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
当我们把一个对象赋值给一个新的变量时, 赋的其实是该对象的在栈中的地址,而不是堆中的数据 。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
浅拷贝是按位拷贝对象, 它会创建一个新对象 ,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。
我们先来看两个例子,对比赋值与浅拷贝会对原对象带来哪些改变?
上面例子中,obj1是原始数据,obj2是赋值操作得到,而obj3浅拷贝得到。我们可以很清晰看到对原始数据的影响,具体请看下表:
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。
注意:当object只有一层的时候,是深拷贝
修改新对象会改到原对象:
同样修改新对象会改到原对象:
关于Array的slice和concat方法的补充说明:Array的slice和concat方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。
原数组的元素会按照下述规则拷贝:
可能这段话晦涩难懂,我们举个例子,将上面的例子小作修改:
原理: 用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
这种方法虽然可以实现数组或对象深拷贝,但不能处理函数。
这是因为 JSON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串,不能接受函数。
递归方法实现深度克隆原理: 遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。
该函数库也有提供 _.cloneDeep 用来做 Deep Copy。
阅读原文
看完文章留完言,还有福利拿,往下看 感兴趣的小伙伴可以在公号【grain先森】后台回复【190313】获取HTML5详解、CSS3详解和Vue详解及实战项目,可以转发朋友圈和你的朋友分享哦。
字符串和数组的操作方法
字符串: 通过 " " 或 ’ ’ 都可以表示字符串,字符串就是普通的文本值,引号中可以写任意字符,引号中的字符仅代表它的字面意思,不表示其他。 字符串的属性: 字符串特点与数组有些相似,字符在字符串中的排列也是有序且连续的. length: 只读属性,会得到一个number类型的值,表示字符串中字符长度(不区分中英文) 可以通过循环遍历字符(字符索引同样从0开始递增+1,最大索引是length-1)。
注意: 字符串是基础数据类型,无法通过为指定下标位置重新赋值来更换字符串中的字符。(字符串的所有操作,都不是对字符串本身操作,都是对字符串的拷贝进行的操作)
注意: 所有的字符串操作方法都不会对调用方法的字符串产生影响,全都是生成了新的字符串。
操作方法:
字符串没有删除字符串的操作方法,如果要删除字符串中的字符,思路就是将要删除的字符替换成空字符串。
10.str.toLowerCase():将字符串转化成小写
数组: 属于object类型,是一个连续且有序可存储多个值的数据结构(容器)。 1、如何声明一个数组
2、length属性,数组的length属性是一个只读属性,值是number类型,表示数组中存放数据的数量(也称数组长度)。
3、元素与索引 元素: 数组中存储的值都称为是数组的元素。 索引:数组元素在数组中的位置用索引表示,索引是从0开始递增的整数。(元素索引值最小是:0,最大是:数组长度-1) 通过索引可以读取数组中与索引位置对应的元素的值。
当读取的索引值超过了索引范围(数组越界),不会报错,会得到undefined
同样可以通过给数组取索引赋值的形式向数组中添加元素,要注意索引的连续性。
可以利用for循环来遍历数组元素(依次访问)
数组的赋值操作(拷贝操作)
number、string、boolean都属于基础数据类型,基础数据类型在进行赋值的时候,是将一个变量的值的拷贝赋值给另一个变量。
深拷贝
object属于引用类型,引用类型在进行赋值的时候,是将值在内存中的地址赋值给了另一个变量,因此两个变量共同指向同一个内存地址。
浅拷贝
基础数据类型比较的是值(字面值)
引用类型比较的是内存地址是否相同,并不会比较字面值。 不存在完全相同的两个对象
数组的属性和操作方法 属性:length, number类型,只读,表示数组元素的个数(数组长度) 操作方法:
(1)添加:第二个参数是0,并且有第三个参数
(2)替换:第二个参数大于0,并且有第三个参数
(3)删除:第二个参数大于0,并且没有第三个参数
未知长度的数组,需要将除了第一个以外的其他元素都删除 (1) 通过循环多次调用pop()
(2) 通过splice删除指定位置的元素
6.indexOf():判断括号中的值是否是数组的元素,如果是将得到元素的索引,如果不是将得到-1。(不会影响原数组) 场景:水果列表中是否包含’牛油果’?
7.concat():合并多个数组(不会影响原数组)
8.slice():对数组进行截取(不会影响原数组) 参数: 第一个参数:设置开始截取的位置 第二个参数:设置结束截取的位置,截取内容不包含结束位置的元素。当结束位置超过数组长度,只会截取到数组末尾,不会报错。
2018WEB前端JavaScript里的深浅拷贝
Javascript有五种基本数据类型(也就是简单数据类型),它们分别是:Undefined,Null,Boolean,Number和String。还含有一种复杂数据类型,就是对象注意Undefined和Null的区别,Undefined类型只有一个值,就是undefined,Null类型也只有一个值,也就是null Undefined其实就是已声明未赋值的变量输出的结果 null其实就是一个不存在的对象的结果var c;console.log(c)//undefinedconsole.log(document.getElementById(’wsscat’))//没有id为wsscat的节点,输出null1234简单的数据类型和复杂的数据类型有以下重要的区别对于简单数据类型它们值在占据了内存中固定大小的空间,并被保存在栈内存中。当一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本,还有就是不能给基本数据类型的值添加属性var a = 1;var b = a;a.attr = ’wsscat’;console.log(a.attr)//undefined上面代码中a就是简单数据类型(Number),b就是a的副本,它们两者都占有不同位置但相等的内存空间对于复杂的数据类型复杂的数据类型即引用类型,它的值是对象,保存在堆内存中,包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针。从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向同一个对象。var obj = {name:’wsscat’,age:0} var obj2 = obj;obj2 = 5;console.log(obj);//Object {name: "wsscat", age: 0, c: 5}console.log(obj2);////Object {name: "wsscat", age: 0, c: 5}我们可以看到obj赋值给obj2后,当我们更改其中一个对象的属性值,两个对象都发生了改变,究其原因局势因为obj和obj2这两个变量都指向同一个指针,赋值只是复制了指针,所以当我们改变其中一个的值就会影响另外一个变量的值浅拷贝其实这段代码就是浅拷贝,有时候我们只是想备份数组,但是只是简单让它赋给一个变量,改变其中一个,另外一个就紧跟着改变,但很多时候这不是我们想要的var obj = {name:’wsscat’,age:0} var obj2 = obj;obj2 = 5;console.log(obj);//Object {name: "wsscat", age: 0, c: 5}console.log(obj2);////Object {name: "wsscat", age: 0, c: 5}深拷贝数组 对于数组我们可以使用slice()和concat()方法来解决上面的问题 silcevar arr = ; var arrCopy = arr.slice(0);arrCopy = ’tacssw’console.log(arr)//concatvar arr = ; var arrCopy = arr.concat();arrCopy = ’tacssw’console.log(arr)//对象 对象我们可以定义一个新的对象并遍历新的属性上去实现深拷贝var obj = { name:’wsscat’, age:0} var obj2 = new Object();obj2.name = obj.name;obj2.age = obj.ageobj.name = ’autumns’; console.log(obj);//Object {name: "autumns", age: 0} console.log(obj2);//Object {name: "wsscat", age: 0}当然我们可以封装好一个方法来处理对象的深拷贝,代码如下var obj = {name: ’wsscat’,age: 0} var deepCopy = function(source) {var result = {}; for(var key in source) { if(typeof source === ’object’) {result)} else {result}} return result;} var obj3 = deepCopy(obj)obj.name = ’autumns’;console.log(obj);//Object {name: "autumns", age: 0}console.log(obj3);//Object {name: "wsscat", age: 0}
更多文章:
photoshop在线版(photoshop网页版免费使用的官网是哪个网址的要正宗的官网的哦!)
2024年7月27日 09:15
清风复古传奇怎么到了27级升不动了?清风传奇1.76网站多少
2024年5月28日 07:51
app自动化测试工具有哪些(有哪些自动化测试的软件开发质量管理平台)
2024年7月24日 12:19
为什么有的老师不建议练瘦金体?范笑歌瘦金体能不能称为当今第一瘦金
2024年6月4日 15:07
电脑经典单机游戏排行(世界范围内销量最高的单机游戏top10,都是经典,你玩过几部)
2024年7月1日 09:07
冰壶比赛中,后手领先2分,为什么不把对手的每一只壶都打走?冰壶游戏真的配得上奥林匹克么
2024年5月11日 02:16
内地能上BBC learning English网吗?怎么听bbc广播
2024年4月6日 02:05
万能钥匙wifi自动解锁(万能钥匙自动连接wifi怎么解密)
2024年6月25日 13:06