JavaScript 中的数据类型可以分为:
- 基本类型:string,number,boolean,undefined,null
- 引用类型:array,object (array 本质上也是 object)
假如存在两个变量,a 和 b ,在执行 a = b 的操作时,基本类型采用值传递,引用类型采用地址传递。关于值传递和地址传递,大概就是,值传递会在内存中单独的开辟一片空间存储数据,a 在内存中有自己的存储空间,b 在内存中也有自己的存储空间,a 和 b 已经没有什么关系了。而地址传递只是增加了一个地址,a 和 b 在内存中,使用的是同一片存储空间,只是通过 a 和 b 都可以找到这片存储空间。这也就解释了,在实际开发中,为什么对 a 的操作,b 也会跟着改变,因为他们操作的是内存中同一个数据。为了避免这个问题,就有了深拷贝。深拷贝就是对于引用类型,不再是只增加一个地址,而是在内存中重新开辟一片存储空间。
实现深拷贝的几种方法:
1. 使用递归的方式实现深拷贝
const deepCopy = function (source) {
if (!source || typeof source !== 'object') {
return source
}
let sourceCopy = source instanceof Array ? [] : {}
for (let key in source) {
sourceCopy[key] = typeof source[key] === 'object' ? deepCopy(source[key]) : source[key]
}
return sourceCopy
}
注意,此方法对于 date 对象,无法实现拷贝。
不过可以对 date 对象单独处理。如下:
var deepCopy = function (source) {
if (!source || typeof source !== 'object') {
return source
}
let sourceCopy = source instanceof Array ? [] : {}
for (let key in source) {
sourceCopy[key] = source[key] instanceof Date
? new Date(source[key])
: typeof source[key] === 'object'
? deepCopy(source[key])
: source[key]
}
return sourceCopy
}
2. 通过 JSON 对象实现深拷贝
const deepCopy = function (source) {
let _source = JSON.stringify(source)
return JSON.parse(_source)
}
注意,此方法无法实现 undefined,function,symbol 这三种类型的数据拷贝,可以拷贝 date 对象,不过形式完全不一样。
symbol 是 es6 新引入的一种数据类型,表示独一无二的值。
以上两种方法,对于对象,数组都是适用的。另外,对象和数组还有自己单独的方法。
对象实现深拷贝的两种方法:
1. Object.assign()
const deepCopy = function (source) {
return Object.assign({}, source)
}
2. es6 展开符
const deepCopy = function (source) {
return {...source}
}
注意,以上两种方法,只能实现一层深拷贝,对于嵌套的对象没有办法实现深拷贝。支持 date 对象。
数组实现深拷贝的两种方法:
1. catch()
const deepCopy = function (source) {
let _source = []
return _source.concat(source)
}
2. slice()
const deepCopy = function (source) {
return source.slice()
}
注意,以上两种方法只能实现一维数组的深拷贝,对于一维以上是浅拷贝。
附上对象和数组的测试代码:
let object1 = {
name: '小明',
age: 18,
work: false,
phone: undefined,
wId: null,
birthday: new Date(),
b: '2021-06-29T03:43:55.213Z',
idCord: Symbol('123'),
hobby: ['篮球', '足球', '排球'],
schoolInfo: {
name: '哈哈大学',
address: '哈哈十里街'
},
skill: function () {
console.log('跳舞')
}
}
let object2 = deepCopy(object1)
object2.name = '罗小黑'
object2.schoolInfo.name = '啦啦大学'
console.log(object1)
console.log(object2)
let arr1 = [
['html', 'css', 'js'],
'jquery',
'vue',
'react',
undefined,
null,
function () {
console.log('haha')
},
Symbol('123'),
new Date()
]
let arr2 = deepClone(arr1)
arr2[1] = 'lodash'
arr2[0][0] = 'h5'
console.log(arr1)
console.log(arr2)