# 浅拷贝与深拷贝

4 min read
Table of Contents

JavaScript 变量有两种不同数据类型:基本类型和引用类型。

基本数据类型是按值访问,可以直接操作保存在变量中的实际值。引用类型的值是保存在堆内存中的对象,JavaScript 不能直接操作对象的内存空间,实际操作的是对象的引用。在传递的时候,基本类型是传值,引用类型是传址。所以,浅拷贝与深拷贝只针对于引用类型这种对象。

浅拷贝与深拷贝

浅拷贝:浅拷贝只拷贝对象的引用地址,并没有创建新的对象,并没有开辟新的堆内存。拷贝出来的变量是同一个引用地址,指向同一个对象。

深拷贝:深拷贝是对引用的对象全部进行拷贝。在内存中创建了新的对象,拷贝出来的变量指向不同的引用地址,指向不同的对象。

浅拷贝的示例

  • 赋值操作
var arr = [1, 2, 3, 4]
var obj = { a: 'a', b: 'b' }
var arrCopy = arr
var objCopy = obj
arrCopy[0] = 0
objCopy.a = 'aa'
log(arr, arrCopy) //[0, 2, 3, 4], [0, 2, 3, 4]
log(obj, objCopy) //{ a: "aa", b: "b" }, { a: "aa", b: "b" }

特别的浅拷贝

当数据只有一层的时候,该方法可以当作深拷贝使用。当数据超过一层时候,只能用作浅拷贝。

  • Array.slice() —常用作数组
var arr = [1, 2, 3, 4]
var arrCopy = arr.slice()
arrCopy.push(5)
log(arr, arrCopy)
//[1, 2, 3, 4], [1, 2, 3, 4, 5]
var arr = [1, 2, 3, 4, [10, 11]]
var arrCopy = arr.slice()
arrCopy[4].push(12)
log(arr, arrCopy)
//[1, 2, 3, 4, [10, 11, 12]], [1, 2, 3, 4, [10, 11, 12]]
  • Ojbect.assign() —常用作对象
var obj = { a: 'a', b: 'b' }
var objCopy = Object.assign({}, obj)
objCopy.a = 'aaa'
log(obj, objCopy)
//{ a: "a", b: "b" }, { a: "aaa", b: "b" }
var obj = { a: 'a', b: 'b', c: { d: 'd' } }
var objCopy = Object.assign({}, obj)
objCopy.c.d = 'ddd'
log(obj, objCopy)
//{ a: 'a', b: 'b', c: {d: "ddd"} }, { a: 'a', b: 'b', c: {d: "ddd"} }
  • 扩展运算符… —数组,对象都常用
var arr = [1, 2, 3, 4]
var obj = { a: 'a', b: 'b' }
var arrCopy = [...arr]
var objCopy = { ...obj }
arr.push(5)
obj.c = 'c'
log(arr, arrCopy) //[1, 2, 3, 4, 5] [1, 2, 3, 4]
log(obj, objCopy) //{ a: "a", b: "b" }, { a: "a", b: "b", c: "c" }

深拷贝

  • JSON.parse 和 JSON.stringify
var obj = { a: { b: 'c' } }
var objCopy = JSON.parse(JSON.stringify(obj))
objCopy.a.b = 'd'
log(obj, objCopy) //{ a: { b: "c"} }, { a: { b: "d"} }

局限性:无法转换function,function会直接消失掉。

var obj = {
fun: function () {
console.log('hi')
},
}
var objCopy = JSON.parse(JSON.stringify(obj))
log(typeof obj.fun) //"function"
log(typeof objCopy.fun) //"undefined"
  • Jquery 的 extend

  • Lodash 的 cloneDeep

题外话

数组的部分方法原本是不改变原数组的,如 map, filter, find…等等。但是如果数组项是对象的话,且遍历时修改原数组项会修改原数组。

const arr = [1, 2, 3]
const arr2 = [{ value: 1 }, { value: 2 }]
const copy = arr.map((i) => {
i += 1
return i
})
const copy2 = arr2.map((i) => {
i.value += 1
return i
})
console.log(arr, copy)
// [1, 2, 3] [2, 3, 4]
console.log(arr2, copy2)
// [{ value: 2 }, { value: 3 }] [{ value: 2 }, { value: 3 }]

More Posts

# 数据结构闲谈

1 min read

从广义上讲,数据结构就是一组数据的存储结构,算法就是操作数据的一组方法。数据结构是为算法服务的,算法要作用在特定的数据结构之上。