资讯专栏INFORMATION COLUMN

js的浅拷贝和深拷贝

jsliang / 3329人阅读

摘要:拷贝分为浅拷贝和深拷贝。浅拷贝是引用复制,深拷贝是完全单纯拷贝数据的值。所以,这种方法只是简单绕过第一层箱子的引用复制深拷贝目前比较好的方法就是大法,要么就是自己写递归的深拷贝函数。附带深拷贝的自定义函数源自大佬的

经常遇到数组或对象等引用类型作为函数的参数的情况,但又不想修改原来的数据,这时候就需要拷贝(基本类型的变量不需要考虑)。
拷贝分为浅拷贝深拷贝。浅拷贝是引用复制,深拷贝是完全单纯拷贝数据的值。因为数组是最常见的引用类型,所以下面大部分拿数组举例。

浅拷贝

简单把引用复制

var a = [1,2,3]
var b = a
console.log(b) //Array(3) [1, 2, 3]
b[1] = 0
console.log(b) //Array(3) [1, 0, 3]
console.log(a) //Array(3) [1, 0, 3]

可以看出,修改数组b的时候,数组a也被修改了。这显然不是想要的做法。

要想不改变原来的数组,就要用到以下的几种方法:

循环 for(...)

concat方法

var a = [1,2,3]
var b = a.concat() //或 var b = [].concat(a)
console.log(b) //Array(3) [1, 2, 3]
b[1] = 0
console.log(b) //Array(3) [1, 0, 3]
console.log(a) //Array(3) [1, 2, 3]

slice方法

var a = [1,2,3,4,5]
var b = a.slice(0)
console.log(b) //Array(5) [1, 2, 3, 4, 5]
b[0] = 0
console.log(a) //Array(5) [1, 2, 3, 4, 5]
console.log(b) //Array(5) [0, 2, 3, 4, 5]

还可以部分拷贝

var a = [1,2,3,4,5]
var b = a.slice(1, 3) //返回[1,3)下标区间的数
console.log(b) //Array(2) [2, 3]
//负数也可以
console.log(a.slice(-2)) //Array(2) [4, 5]

还有一种方法,跟循环的方法有点类似,就是es6的新特性,展开语法:

var a = [1,2,3,4,5]
var b = [...a]
b[0] = 0
console.log(a) //Array(5) [1, 2, 3, 4, 5]

这个方法就是逐一枚举a中的值,放到空数组中

但是,以上这几种拷贝方法看似都不会改变原来数组,其实也还是属于浅拷贝范畴。如果原数组里面还有引用类型数组,这些方法都会失效(比如二维数组)

var a = [[1,2,3],[4,5,6]]
var b = a.slice(0)
b[0][4] = 0
console.log(a[0]) //[[1, 2, 0],[4,5,6]]

其他concat,[...]等方法也一样。
可以这么理解:原数组就像一个带锁的独一无二的箱子,里面有各种零食。简单的引用复制,其实就是配了一把钥匙,谁动过里面的东西,其他人都会受到影响。而上面这4种方法其实就是自己买一个不同箱子,参照原来的箱子里面的零食,去某宝买同款。动自己箱子的东西,原来的箱子不受影响。但是如果原来的箱子里面还套了个独一无二带锁的箱子,某宝买不到同款,那没办法,里面的箱子只能还是配把钥匙共用。所以,这4种方法只是简单绕过第一层箱子的引用复制

深拷贝

目前比较好的方法就是json大法JSON.stringify(),要么就是自己写递归的深拷贝函数。
JSON.stringify()是将对象或数组序列化成字符串。然后再用JSON.parse()解析成值或对象。

var a = {aa:1,bb:[1,2],cc:[3,4]}
var b = JSON.parse(JSON.stringify(a))
console.log(b) //{aa:1,bb:[1,2],cc:[3,4]}
b.cc[0] = 0
console.log(a) //{aa:1,bb:[1,2],cc:[3,4]}
console.log(b) //{aa:1,bb:[1,2],cc:[0,4]}

附带深拷贝的自定义函数(源自大佬mqyqingfeng的github)

var deepCopy = function(obj) {
    if (typeof obj !== "object") return;
    var newObj = obj instanceof Array ? [] : {};
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = typeof obj[key] === "object" ? deepCopy(obj[key]) : obj[key];
        }
    }
    return newObj;
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96348.html

相关文章

  • JavaScript中的浅拷贝和深拷贝

    摘要:在中可以通过添加一个参数来实现递归,调用就可以实现一个深拷贝。利用序列化实现一个深拷贝 在JavaScript中,对于Object和Array这类引用类型值,当从一个变量向另一个变量复制引用类型值时,这个值的副本其实是一个指针,两个变量指向同一个堆对象,改变其中一个变量,另一个也会受到影响。 这种拷贝分为两种情况:拷贝引用和拷贝实例,也就是我们说的浅拷贝和深拷贝 浅拷贝(shallow...

    ernest.wang 评论0 收藏0
  • JS的浅拷贝和深拷贝

    摘要:说明外层数组拷贝的是实例说明元素拷贝是引用深拷贝在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,拷贝后的对象与原来的对象完全隔离,互不影响。中的方法可以实现深拷贝,源码原理也是递归使用浅拷贝。 1.浅拷贝 当把数组或对象简单赋值给其他变量的时候,实际上进行的是浅拷贝,浅拷贝是拷贝引用,只是将拷贝后的引用指向同一个对象实例,彼此间的操作还会互相影响。 分为两种情况:直接拷贝源对象...

    xeblog 评论0 收藏0
  • js的浅拷贝和深拷贝和应用场景

    摘要:而大多数实际项目中,我们想要的结果是两个变量初始值相同互不影响。所以就要使用到拷贝分为深浅两种深浅拷贝的区别浅拷贝只复制一层对象的属性,而深拷贝则递归复制了所有层级。 为什么会用到浅拷贝和深拷贝 首先来看一下如下代码 let a = b = 2 a = 3 console.log(a) console.log(b) let c = d = [1,2,3] let e = f = {a:...

    MartinDai 评论0 收藏0
  • js的浅拷贝和深拷贝和应用场景

    摘要:而大多数实际项目中,我们想要的结果是两个变量初始值相同互不影响。所以就要使用到拷贝分为深浅两种深浅拷贝的区别浅拷贝只复制一层对象的属性,而深拷贝则递归复制了所有层级。 为什么会用到浅拷贝和深拷贝 首先来看一下如下代码 let a = b = 2 a = 3 console.log(a) console.log(b) let c = d = [1,2,3] let e = f = {a:...

    nemo 评论0 收藏0
  • js的浅拷贝和深拷贝和应用场景

    摘要:而大多数实际项目中,我们想要的结果是两个变量初始值相同互不影响。所以就要使用到拷贝分为深浅两种深浅拷贝的区别浅拷贝只复制一层对象的属性,而深拷贝则递归复制了所有层级。 为什么会用到浅拷贝和深拷贝 首先来看一下如下代码 let a = b = 2 a = 3 console.log(a) console.log(b) let c = d = [1,2,3] let e = f = {a:...

    lavor 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<