const originArray = [1, 2, [6, 7], 3, 4, 5];
let shallowCopyArr = [];
let deepCopyArr = [];
const originObject = { a: 1, b: {c: 3} };
let shallowCopyObj = {};
let deepCopyObj = {}const arrayLike = {
0: "AAA",
1: [1, 2],
2: "BBB",
length: 3
};
let shallowCopyArrLike = [];
let deepCopyArrLike = [];
1. 浅拷贝
引用的复制
- 浅拷贝实现:赋值操作符
- "首层浅拷贝"实现:
对象:遍历、Object.assign、扩展运算符
数组(类数组对象):遍历、扩展运算符、Array.from、slice、concat、filter、map、reduce等数组方法
(注意:所有的数组标准方法都适用于数组和类数组对象,只有concat例外, 具体使用参考js伪数组对象)
for (const prop in originObject) {
if (originObject.hasOwnProperty(prop)) {
shallowCopyObj[prop] = originObject[prop];
}
}
shallowCopyObj.a = 2;
shallowCopyObj.b.c = 4;
shallowCopyObj// { a: 2, b: {c: 4} }
originObject// { a: 1, b: {c: 4} }----------arrayLike[Symbol.isConcatSpreadable] = true;
shallowCopyArrLike = [].concat.call(arrayLike, [7, 8]);
shallowCopyArrLike.push(8)
shallowCopyArrLike[2].push(3)
shallowCopyArrLike// ['AAA', [1,2,3], 'BBB', 7, 8, 3]
arrayLike
// const arrayLike = {
//0: "AAA",
//1: [1, 2, 3],
//2: "BBB",
//length: 3
// };
2. 深拷贝
堆内存的重新分配【js深浅拷贝梳理】实现:对象、数组、类数组对象通用
- 递归
- JSON.parse, JSON.stringify
- jquery.extend()
const originObject = { a: 1, b: { c: 3 }, d: undefined, e: Array, f: Symbol('foo') };
const originArray = [1, 2, [6, 7], 3, 4, 5, undefined, Array];
deepCopyObj = JSON.parse(JSON.stringify(originObject));
deepCopyArr = JSON.parse(JSON.stringify(originArray));
deepCopyObj.a = 2;
deepCopyObj.b.c = 4;
deepCopyObj// { a: 2, b: {c: 4} }
deepCopyArr// [1, 2, [6, 7], 3, 4, 5, null, null]实现限制:
1. 非数组对象的属性值为undefined、函数、Symbol值时在序列化时被忽略, 数组中会转化为null
2. 无法处理循环引用的对象
递归实现:
关键点在于
- 拷贝环问题
- Date、Reg等引用类型的拷贝
- 函数的拷贝
const obj = {
a:1,
c: [1,2],
d: {
e: 1,
},
f: null,
};
obj.g = obj;
function isObject(target) {
return (typeof target === 'object' || typeof target === 'function') && target !== null
}
function clone(target) {
// WeakMap对键名的引用为弱引用,有利于垃圾回收机制
const vm = new WeakMap();
function deepClone(target) {
if (isObject(target)) {
if (vm.has(target)) return vm.get(target);
let cloneTarget = Array.isArray(target) ? [] : {};
vm.set(target, cloneTarget);
for (const key in target) {
cloneTarget[key] = deepClone(target[key]);
}
return cloneTarget;
} else {
return target;
}
};
return deepClone(target);
}
const obj1 = clone(obj)
obj1.c[1] = 5;
obj1.f = [1,2];
console.log(obj1)// {a: 1, c: [1,5], d: {e: 1}, f: [1,2], g: {...} }
(2) Date、Reg等引用类型的拷贝
使用constructor/Object.prototype.toString.call判断类型,根据不同引用类型做相应处理
未完待续........
(3) 函数、不可枚举属性等的拷贝
有这时间研究不如使用现成的工具库lodash.cloneDeep
推荐阅读
- 操作系统|[译]从内部了解现代浏览器(1)
- web网页模板|如此优秀的JS轮播图,写完老师都沉默了
- JavaScript|vue 基于axios封装request接口请求——request.js文件
- vue.js|vue中使用axios封装成request使用
- JavaScript|JavaScript: BOM对象 和 DOM 对象的增删改查
- JavaScript|JavaScript — 初识数组、数组字面量和方法、forEach、数组的遍历
- JavaScript|JavaScript — call()和apply()、Date对象、Math、包装类、字符串的方法
- JavaScript|JavaScript之DOM增删改查(重点)
- javascript|vue使用js-xlsx导出excel,可修改格子样式,例如背景颜色、字体大小、列宽等
- javascript|javascript中的数据类型转换