夜下客

繁体版 简体版
夜下客 > JS修炼法则 > 第4章 JS类型判断

第4章 JS类型判断

if (typeof target === 'object' && target !== null) {

const cloneTarget = Array.isArray(target) ? []: {};

for (let prop in target) {

if (target.hasOwnProperty(prop)) {

cloneTarget[prop] = target[prop];

return cloneTarget;

} else {

return target;

};

4-2. 深拷贝

4-2-1. 定义

深拷贝复制一个完全相同的对象,从堆内存中开辟一个新的区域存放该对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

4-2-2. 代码实现

4-2-2.(1). JSON.stringify

原理:将一个对象序列化成为 JSON 的字符串,并将对象里面的内容转换成字符串,最后再用 JSON.parse() 的方法将JSON 字符串生成一个新的对象。

缺点:

原对象中的属性有函数、undefined、Symbol类型时,其键值对会消失。

拷贝 Date 引用类型会变成字符串。

无法拷贝不可枚举的属性。

无法拷贝对象的原型链。

拷贝 RegExp 引用类型会变成空对象。

对象中含有 NaN、Infinity 以及 -Infinity,JSON 序列化的结果会变成 null。

无法拷贝对象的循环应用,即对象成环 (obj[key] = obj)。

代码例子:

let source = { a:1, b:[1,2,3] }

let tempStr = JSON.stringify(source);

let target = JSON.parse(tempStr);

4-2-2.(2). 手撕递归实现

原理:通过 for in 遍历传入参数的属性值,如果值是引用类型则再次递归调用该函数,如果是基础数据类型就直接复制。

缺点:(同 JSON.stringify方案)

不能复制不可枚举的属性以及 Symbol 类型。

只是针对普通的引用类型的值做递归复制,而对于 Array、Date、RegExp、Error、Function 这样的引用类型并不能正确地拷贝。

对象的属性里面成环,即循环引用没有解决。

代码实现如下:

const deepClone = obj => {

let cloneObj = {}

for(let key in obj) {

if(typeof obj[key] ==='object') {

cloneObj[key] = deepClone(obj[key]);

} else {

cloneObj[key] = obj[key];

return cloneObj;

4-2-2.(3). 递归优化

原理:解决上一个方案的缺点

针对能够遍历对象的不可枚举属性以及 Symbol 类型,我们可以使用 Reflect.ownKeys 方法。

当参数为 Date、RegExp 类型,则直接生成一个新的实例返回。

利用 Object 的 getOwnPropertyDescriptors 方法可以获得对象的所有属性,以及对应的特性,顺便结合 Object 的 create 方法创建一个新对象,并继承传入原对象的原型链。

利用 WeakMap 类型作为 Hash 表,因为 WeakMap 是弱引用类型,可以有效防止内存泄漏(你可以关注一下 Map 和

『加入书签,方便阅读』