数据类型:说到拷贝,就首先需要谈谈堆栈和数据类型了,数据类型分为基本数据类型和引用数据类型,基本数据类型包括number,string,boolean,null 和 undefined这五类,而引用数据类型是由基本数据类型组成的复杂的对象,而深拷贝本身只针对较为复杂的object类型的数据。
堆和栈内存:接下来说一下堆栈的存储空间,基本数据类型的名和值是都存在栈内中的,即有名可以直接读出值;而对于引用数据类型,它的名也是存在栈内存中,而它的真正的值是存在堆内存中的,那么它的名和值是怎么联系起来的呢,就是通过也存在栈内存中的真正的值在堆内存中的存储路径,即引用类型的数据在栈中存储的是名和值对应的引用地址。
深拷贝和浅拷贝:
1、使用数据类型
深拷贝和浅拷贝只针对像 Object
, Array
这样的复杂对象的,String
,Number
等简单类型不存在深拷贝。
2、浅拷贝
因为浅拷贝只会将对象的各个属性进行依次复制,并不会进行递归复制。在JavaScript中,对于
Object
和 Array
这类引用类型值,当从一个变量向另一个变量复制引用类型值时,这个值的副本其实是一个指针,两个变量指向同一个堆对象,改变其中一个变量,另一个也会受到影响。所以浅拷贝会导致 obj.arr
和 shallowObj.arr
指向同一块内存地址,当修改 obj.arr
的值时, shallowObj.arr
的值同样会被修改 3、深拷贝
而深拷贝则不同,它不仅将原对象的各个属性逐个 复制出去,而且将原对象各个属性所包含的对象也依次采用深拷贝的方法 递归复制到新对象上。这就不会存在上面
obj
和 shallowObj
的 arr
属性指向同一个对象的问题。当修改 obj.arr
的值时, shallowObj.arr
的值不会被修改,仍然为原值 实现深拷贝的方法:
1、可以递归去复制数据的所有层级的属性
function cloneDeeply(obj){ //定义一个拷贝的对象 let objClone = Array.isArray(obj)?[]:{}; //传入的数据是对象类型的 if(obj && typeof obj==="object"){ for(key in obj){ //判断是否是自身的属性方法,所有函数和原型成员会被有意忽略 if(obj.hasOwnProperty(key)){ //判断ojb子元素是否为对象,如果是,递归复制 if(obj[key]&&typeof obj[key] ==="object"){ objClone[key] = deepClone(obj[key]); }else{ //如果不是,简单复制 objClone[key] = obj[key]; } } } } return objClone;}
2、
JSON.parse(JSON.stringify(obj))方法实现深拷贝
该用法简单,然而使用这种方法会有一些隐藏的坑:因为在序列化JavaScript对象时,所有函数和原型成员会被有意忽略。故只能拷贝纯json的,不能拷贝包含函数的对象)。 通俗点说,
JSON.parse(JSON.stringfy(X))
,其中X只能是 Number
, String
, Boolean
, Array
, 扁平对象,即那些能够被 JSON 直接表示的数据结构。 function cloneDeeply(obj){ let _obj = JSON.stringify(obj), objClone = JSON.parse(_obj); return objClone}
3、另外JQuery也提供了一个对象扩展的方法extend进行属性的深浅复制,可配置
jQuery.extend() 函数用于将一个或多个对象的内容合并到目标对象。
注意:1. 如果只为$.extend()指定了一个参数,则意味着参数target被省略。此时,target就是jQuery对象本身。通过这种方式,我们可以为全局对象jQuery添加新的函数。
2. 如果多个对象具有相同的属性,则后者会覆盖前者的属性值。 4、特殊情况
slice的一级是深拷贝,多级则是浅拷贝(记住深拷贝是拷贝对象所以层级的属性)
es6中的展开符号... 也是浅拷贝
https://www.cnblogs.com/echolun/p/7889848.html#undefined