深浅拷贝
赋值
赋值是将某一数值或对象赋给某个变量的过程,分为下面 2 部分
- 基本数据类型:赋值,赋值之后两个变量互不影响
- 引用数据类型:赋址,两个变量具有相同的引用,指向同一个对象,相互之间有影响
浅拷贝
创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
简单实现一个浅拷贝:
1 | function shallowClone(obj) { |
在JavaScript中,存在浅拷贝的现象有:
Object.assign:用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。Array.prototype.slice():方法返回一个新的数组对象,这一对象是一个由begin和end(不包括end)决定的原数组的浅拷贝。Array.prototype.concat():用于合并两个或多个数组。不会更改现有数组,而是返回一个新数组。- 使用拓展运算符(…)实现的复制
深拷贝
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。拷贝前后两个对象互不影响。
常见的深拷贝方式有:
JSON.parse(JSON.stringify(object))但是该方法有以下几个问题:
1、会忽略
undefined2、会忽略
symbol3、不能序列化函数
4、不能解决循环引用的对象
5、不能正确处理
new Date()6、不能处理正则
lodash.cloneDeep()jQuery.extend()手写循环递归
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19function deepClone(obj, hash = new WeakMap()) {
if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// 可能是对象或者普通的值 如果是函数的话是不需要深拷贝
if (typeof obj !== "object") return obj;
// 是对象的话就要进行深拷贝
if (hash.get(obj)) return hash.get(obj);
let cloneObj = new obj.constructor();
// 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
hash.set(obj, cloneObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 实现一个递归拷贝
cloneObj[key] = deepClone(obj[key], hash);
}
}
return cloneObj;
}
总结
前提为拷贝类型为引用类型的情况下:
- 浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址
- 深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址
- 本文标题:深浅拷贝
- 本文作者:灵感胜于汗水
- 创建时间:2022-11-01 14:09:42
- 本文链接:https://cjhsyc.github.io/2022/11/01/深浅拷贝/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!