美文网首页摄影
浅复制(浅拷贝)和深复制(深拷贝)

浅复制(浅拷贝)和深复制(深拷贝)

作者: locky丶 | 来源:发表于2019-04-29 19:29 被阅读0次

js存储机制

JS中对象分为基本类型和复合(引用)类型,基本类型存放在栈内存,复合(引用)类型存放在堆内存。
堆内存用于存放由new创建的对象,栈内存存放一些基本类型的变量和对象的引用变量。

1.基本类型
如 变量,在创建时会直接复制一份。

var a = 'hello men'
var b = a
b = "good"
console.log(a) // hello men
console.log(b) // good

当b改变时,不会影响初始变量a

2.复合类型
如数组、对象等,js就会做引用,原对象和拷贝对象会做关联

var arr1 = [1, 2, 3, 4]
var arr2 = arr1
arr2[4] = 9
console.log(arr1)  // [1,2,3,4,9]
console.log(arr2)  // [1,2,3,4,9]

arr2改变时arr1也随之改变,这里举了数组的例子,对象也类似。

浅与深的区别

为了让拷贝对象 和 原对象完全脱离关系,我们需要用到浅拷贝、深拷贝这两种方法。

浅拷贝只能复制根属性,做不到真正的全拷贝。
深拷贝能实现真正的全拷贝,与原对象分清界限。

浅拷贝

我们先从简单的入手,浅浅的拷贝一个数组。

  • 方法1
var array1 = ['a', 'b', 'c']
var array2 = array1.slice() // 单个复制数组元素
array2[3] = 'h'
console.log(array1) // ['a','b','c']
console.log(array2) // ['a','b','c', 'h']
  • 方法2
var arr1 = [1, 2, 3]
var arr2 = []
var copy = (arr1, arr2) => {
    arr1.forEach((element, index) => {
        arr2[index] = element
    })
    return arr2
}
arr2 = copy(arr1, arr2)
arr2[3] = 6
console.log(arr2) // [ 1, 2, 3, 6 ]
console.log(arr1) // [ 1, 2, 3 ]

array2只改变自己,不影响他人,是个好同志。
现在难度升级,我们在数组里加入了对象。

var array1 = ['a', 'b', 'c', {
    "name": 'leo'
}]
var array2 = array1.slice()
array2[3].name = 'mark'
console.log(array1) // ['a','b','c',{name: 'mark'}]
console.log(array2) // ['a','b','c',{name: 'mark'}]

这时候改变array2,array1也跟着变了,哦NO!

深拷贝

现在是该大英雄出场了,“深拷贝!深拷贝!”
不啰嗦,直接上代码。

// 创建了 一个带数组和对象的元素 (这还是比较简单的对象结构)
var array1 = ['a', 'b', 'c', { "name": 'leo'}, [8, 9]]
var array2 = []
// 创建拷贝方法 
var copy = (obj1, obj2) => {
    obj1.forEach((item, index) => {
               // 判断该索引值是否为数组
        if (obj1[index].constructor === Array) {
            obj2[index] = []
            obj1[index].forEach((subItem, subIndex) => {
                obj2[index][subIndex] = subItem
            })
                // 判断该索引值是否为对象
        } else if (obj1[index] && typeof obj1[index] === 'object') {
            obj2[index] = {}
            for (let element in obj1[index]) {
                obj2[index][element] = obj1[index][element]
            }
                // 不是对象,说明是属性,直接赋值
        } else {
            obj2[index] = item
        }
    })
    return array2
}

var array2 = copy(array1, array2)
// 改变对象的属性值
array2[3].name = 'mark'
// 改变数组的值
array2[4][1] = '5'
console.log(array2) // [ 'a', 'b', 'c', { name: 'mark' }, [ 8, '5' ] ] 
console.log(array1) // [ 'a', 'b', 'c', { name: 'leo' }, [ 8, 9 ] ] 

恭喜你,我们向要的都实现了!

深不可测的深拷贝 (递归)

有些对象是后台传给我们的,拿到之前不知道里面是什么结构。这种数据着么去拷贝呢?
是时候展示真正的技术了, 那就是递归
递,层层递进。归,归去来兮。
总结下来就是...还是不解释了。
看代码:

// 创建一个深层嵌套的对象
var json1 = {
    "name": "leo",
    "age": 20,
    "child": [{
            "eye": "blue",
            "child": [{
                "photo": "nice"
            }, {
                "photo": "beautiful"
            }]
        },
        {
            "eye": "red",
            "child": []
        }
    ]
}

var json2 = {}
function copy(obj1, obj2) {
    for (var name in obj1) {
        if (typeof obj1[name] === "object") {
            obj2[name] = (obj1[name].constructor === Array) ? [] : {}
           // 递归时改变当前参数位置,
           // 举例:当前name为child时,copy中的参数被替换为 (obj1.child, obj2.child)
            copy(obj1[name], obj2[name])
        } else {
            obj2[name] = obj1[name]
        }
    }
    return obj2
}

json2 = copy(json1, json2)
json2.child[0].eye = 'green'
console.log(json1) // child: [ { eye: 'blue', child: [Object] }
console.log(json2) // child: [ { eye: 'green', child: [Object] }

最简单的深拷贝

先把对象使用JSON.stringify()转为字符串,再赋值给另外一个变量,然后使用JSON.parse()转回来即可。

let a = {
  a1: 1,
  a2: '2',
  a3: [1, 2, 3, 4, 5, 6],
  a4: {
    deep1: 1,
    deep2: 2
  }
}

let b = JSON.parse(JSON.stringify(a))
console.log(b)
a.a4.deep1 = 99
console.log(a)  // a的属性值变动了
console.log(b) // b没变

new

顺带提下,用new 创建的对象,都是引用原对象的。new常常和构造函数一起出现,用于创建对象的继承关系。
我们应尽量避免引用类型的直接拷贝,这样会改变原对象的属性,在协同工作时会产生不可预期的错误。
可以用新的方法Object.create()来创建,或者定义一个空的 F(){} 构造函数做衔接。

参考: https://www.jianshu.com/p/0d7bd31ccf43

相关文章

  • java 对象的拷贝

    拷贝:即复制 对象拷贝:即对象复制 java 对象拷贝分类:浅拷贝、深拷贝 java 对象的浅拷贝和深拷贝针对包含...

  • JS深浅拷贝

    浅拷贝 浅拷贝的意思就是只复制引用,而未复制真正的值。 深拷贝 深拷贝就是对目标的完全拷贝,不像浅拷贝那样只是复制...

  • 17.是否了解 深拷贝 和 浅拷贝 的概念,集合类深拷贝如何实现

    深拷贝内存拷贝 浅拷贝指针拷贝 浅拷贝 深拷贝 集合的浅复制 (shallow copy) 集合的浅复制有非常多种...

  • 浅拷贝和深拷贝

    本文参考:JavaScript中的浅拷贝和深拷贝js 深拷贝 vs 浅拷贝深入剖析 JavaScript 的深复制...

  • 面试题iOS

    面试blog 1、深拷贝浅拷贝:浅拷贝就是拷贝对象的指针,而不复制引用对象本身;深拷贝就是拷贝引用对象本身;浅复制...

  • iOS全解11:特殊问题

    1、浅拷贝和深拷贝的区别? 浅拷贝:只复制指向对象的指针,指针指向同一个地址,而不复制引用对象本身。深拷贝:复制引...

  • python中的浅拷贝和深拷贝

    浅拷贝和深拷贝: 浅拷贝 shallow copy 浅拷贝是指在对象复制过程中,只复制一层变量,不会复...

  • iOS开发 图文并茂理解深拷贝与浅拷贝

    深拷贝和浅拷贝(Shallow copy 和 Deep copy) 一.概念定义 对象复制有两种:浅拷贝和深拷贝。...

  • 拷贝与内存管理

    一、关于深拷贝和浅拷贝的总结 理解 本质上我认为区别在于复制是是指针复制(浅拷贝)还是复制到新的地址上(深拷贝) ...

  • 浅拷贝和深拷贝

    浅拷贝和深拷贝都是只针对Object,Array这样的复杂对象。浅拷贝只复制一层对象的属性,而深拷贝则是递归复制了...

网友评论

    本文标题:浅复制(浅拷贝)和深复制(深拷贝)

    本文链接:https://www.haomeiwen.com/subject/ocmjnqtx.html