js中的赋值操作是深拷贝还是浅拷贝呢?,其实基本数据类型的赋值操作,是深拷贝即两个变量间不会互相影响,对于引用数据类型,赋值操作只是在栈中新增一个指向堆中对象的变量,即复制引用地址。新旧变量之间会互相影响,即在新变量上改变对象值,旧变量对应值也会改变。即浅拷贝。
浅拷贝即只是拷贝一层,更深层次对象级别的只拷贝了地址。 即浅拷贝只是拷贝了数据在栈中的引用,并没有拷贝在堆中的地址本身。
实现浅拷贝的方法: 基本类型数据直接赋值或者使用在es6的Object.assign
Object.assign(target, ...sources)
- target:要拷贝给谁
- source:要拷贝的对象
深拷贝是完完全全的拷贝,新旧变量之间不会相互影响。
对于参数是否是对象有不同的处理方法,如果是对象,对于对象的每个属性和值赋值然后递归处理; 否则直接返回。
实现深拷贝的方法: 使用Json.stringify()将要拷贝的对象转成字符串,然后用Json.parse将字符串转回对象, 但是这个方法存在缺陷 问题:
- 造成数据丢失和数据异常(null)
- function、undefined 直接丢失
- NaN、Infinity 和-Infinity 变成 null
RegExp、Error对象只得到空对象;
递归实现
function deepCopy(obj) {
// 判断拷贝的数据是对象还是数组 生成定义的数据
var copy = Array.isArray(obj) ? [] : {}
for (key in obj) {
// 循环的时候如果此项为引用类型,需要 在一次的将引用类型里面的值取出来
if (typeof obj[key] == 'object') {
// 再次调用该方法取数据
copy[key] = deepCopy(obj[key])
} else {
copy[key] = obj[key]
}
}
return copy
}
但是递归存在同样问题,数据会丢失存在循环引用的问题导致死循环。需要在储存数据前判断是否被拷贝过数据。
function cloneDeep3(source, uniqueList) {
if (!isObject(source)) return source
if (!uniqueList) uniqueList = [] // 新增代码,初始化数组
var target = Array.isArray(source) ? [] : {}
// 要是有 别再循环拷贝了 直接返回 该值
var uniqueData = find(uniqueList, source)
if (uniqueData) {
return uniqueData.target
}
// 数据不存在,保存源数据,以及对应的引用
uniqueList.push({
source: source,
target: target
})
// =============
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (isObject(source[key])) {
target[key] = cloneDeep3(source[key], uniqueList) // 新增代码,传入数组
} else {
target[key] = source[key]
}
}
}
return target
}
// 新增方法,用于查找
function find(arr, item) {
for (var i = 0; i < arr.length; i++) {
if (arr[i].source === item) {
return arr[i]
}
}
return null
}
实际上在开发中最常用的方法还是引入第三方包loadsh直接深拷贝
安装命令:npm i loadsh
直接引用即可 import {cloneDeep} from loadsh