浅克隆
- 把对象进行克隆
//1. Object.assign() let obj = { a:1, b:2, c:3 }; let new_obj = Object.assign({},obj); new_obj === obj // false // 2. 还可以通过循环实现对象的克隆 let new_obj = {}; _.each(obj, (value, key) => { //_.each调用的是自己封装的utils.js中的each方法 new_obj[key] = value; }); // ...
- 把数组进行克隆
let ary = [1,2,3,4,5]; // let new_ary = ary.slice(); // let new_ary = ary.slice(0); // let new_ary = ary.splice(0); // let new_ary = ary.concat([]); // let new_ary = ary.concat(); // let new_ary = [...ary]; // ... //new_ary === ary // => false
以上的方案都是浅克隆:
深度克隆
方法一:JSON.parse(JSON.stringify([value])):
- JSON.stringify([value]) : 把对象/数组变为JSON字符串
- JSON.parse([value]) : 把JSON字符串变为对象/数组【浏览器需要重新开辟所有内存】
- 弊端:
- 不允许出现套娃现象,例如:
window. window = window
- 属性值不能是BigInt
- 丢失一些内容:属性值为symbol/ undefined/ function …
- 部分信息不准确:
- 正则 -> 空对象
- Error -> 空对象
- 日期对象 -> 转换时刻的时间字符串
- …
- 不允许出现套娃现象,例如:
- 属性值要避开以上类型数据
方法二:Qs.parse(Qs.stringify([val]))
- Qs.stringify([value]) : 把对象/数组变为urlencoded格式字符串 : “ xxx=xxx&xxx=xxx ”
- Qs.parse([value]) : 把urlencoded格式字符串变为对象/数组【浏览器需要重新开辟所有内存】
- 弊端:
- 不允许出现套娃现象,例如:
window. window = window
- 丢失一些内容:属性值为 正则表达式/ undefined/ Error …
- 部分信息不准确:
- 布尔值 -> 字符串
- 数字 -> 字符串
- symbol -> 字符串
- BigInt -> 字符串
- null -> “”
- 日期 -> 转换时刻的时间字符串
- …
- 不允许出现套娃现象,例如:
- 属性值要避开以上类型数据
数组/对象的深浅拷贝(克隆)
// 实现数组和对象深/浅拷贝
var clone = function clone() {
var target = arguments[0],//目标元素,被拷贝的值
deep = false,//是否深拷贝
type,//传入的数据类型
isArray,//是否是数组
isObject,//是否是对象
result,//拷贝后的结果,最后返回拷贝后的结果
Ctor,//当前数据所属的类
treated = arguments[arguments.length - 1];//标记是否处理过
//treated不是数组,或者treated.treated部位true,就是没处理过,添加处理标记,否则什么也不做
!Array.isArray(treated) || !treated.treated ? (treated = [], treated.treated = true) : null;
//如果第一个参数是布尔值,则需要要处理深拷贝问题,target取第二个参数
if (typeof target === "boolean") {
deep = target;
target = arguments[1];
};
// 防止死递归的处理
if (treated.indexOf(target) > -1) return target;
treated.push(target);
// 校验类型
type = toType(target);
isArray = Array.isArray(target);//是否是数组
isObject = isPlainObject(target);//是否是纯对象,isPlainObject来自utils.js
// 特殊值的拷贝
//只是null或者undefined 直接返回
if (target == null) return target;
Ctor = target.constructor;//获取当前数据所属的类
//正则或者数据直接new操作
if (/^(regexp|date)$/i.test(type)) return new Ctor(target);
//错误类型new操作传入的是error.message
if (/^(error)$/i.test(type)) return new Ctor(target.message);
//函数返回一个匿名函数,直接执行传入函数,并把参数传递给匿名函数,函数的直接结果和传入的函数执行结果一致
if (/^(function|generatorfunction)$/i.test(type)) {
return function proxy() {
var args = Array.from(arguments);
return target.apply(this, args);
};
};
// 其余既不是数组又不是对象的直接返回
if (!isArray && !isObject) return target;
// 如果是数组/对象,我们依次迭代赋值给新的数组/对象
result = new Ctor();
//遍历target, each为utils内封装的遍历数组/对象的方法
each(target, function (copy, name) {
if (deep) {
// 深拷贝:基于递归再次处理
result[name] = clone(deep, copy, treated);
return;
}
// 浅拷贝
result[name] = copy;
});
return result;
};
utils.js:封装了一些常用的方法