在JS中,数据类型分为基本数据类型和引用数据类型两种。对于基本数据类型来说,它的值直接存储在栈内存中,而对于引用类型来说,它在栈内存中只是存储了一个指向对内存的引用,而真正的数据存储在堆内存中。
object、array 这两个就是引用类型,当我门直接去拷贝的话(copyObj = obj), 拷贝的是指obj的引用,当你修改copyObj时候,obj也会同时改变;数组也一样道理。
深拷贝
深拷贝,要实现的效果是不管对象或数组里面嵌套了多少层引用类型,都能拷贝出来,而非只拷贝它的引用
要实现深拷贝的方法常用有一下方法:
JSON.parse、JSON.stringify
let obj2 = JSON.parse(JSON.stringify(obj1))
缺点:undefined、function、symbol 会在转换过程中被忽略
递归深拷贝
// 不支持循环引用
function deepCopy (src) {
if (!src || typeof src !== 'object') return src // 判断是否为array || object
let temp = Array.isArray(src) ? [] : {}
for (let key in src) {
if (src.hasOwnProperty(key)) { // 过滤继承来的属性
if (src[key] && typeof src[key] === 'object') { // 若属性也是引用类型
temp[key] = deepCopy(src[key]) // 递归克隆
} else {
temp[key] = src[key] // 非引用类型就直接拷贝
}
}
}
return temp
}
let obj2 = deepCopy(obj1)
浅拷贝
那么浅拷贝,简单引用类型直接赋值
或者引用类型的首层进行了深拷贝,但是属性中还有引用类型,只是拷贝它的引用,这样的情况下,也为浅拷贝
以下浅拷贝方法,都只是实现了首层的深拷贝,当嵌套引用类型就要只会拷贝它的引用
ES6扩展运算符
let obj2 = {...obj1} // 对象浅拷贝
let arr2 = [...arr1] // 数组浅拷贝
Object.assign()
let obj2 = Object.assign({}, obj1)
遍历
let shallowCopy = obj => {
let temp = {}
// 遍历对象
for (let key in obj) {
// 只复制本身拥有的属性(非继承过来的属性)枚举属性
if (obj.hasOwnProperty(key)) {
temp[key] = obj[key]
}
}
return temp
}
let obj2 = shallowCopy(obj1)
concat()
let arr2 = [].concat(arr1)