JavaScript 中的数据类型可以分为:
假如存在两个变量,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)