关于前端:数据的深拷贝实现原理

2次阅读

共计 1250 个字符,预计需要花费 4 分钟才能阅读完成。

1. 数据的浅拷贝

let obj = {
    a: 1,
    b: 2,
    c: {d: 99}
};

若要拷贝以后 obj,能够应用 for 循环顺次复制其键值,也能够应用扩大运算符。

let newObj = {...obj};
newObj.c.d = 100;
console.log(obj);    //{a: 1, b: 2, c: { d: 100} }

拷贝后的值应与旧值无关,若扔存在关联则是浅拷贝。这里对新值进行批改,旧值也产生了扭转,表明在复制 obj 时,将 c 属性的对象援用地址也拷贝过来了,造成了新值对旧值的援用地址批改。

这里能够再看一下数组的操作:

let arr = [1, 2, 3, [4]]; 
let newArr = arr.slice(0)
newArr[3][0] = 100;

console.log(arr);    //[1, 2, 3, [ 100] ]

通过 slice 办法将 arr 的值全副截取,并赋值给 newArr。这里对新值的数组元素进行操作,也影响到了旧值,因而 slice 做到的是也是浅拷贝。

2. 实现深拷贝

那么,咱们如何实现深拷贝呢?

1. 对以后数据类型进行校验

2. 数据的循环援用问题

以上两点是数据深拷贝的实现思路,首先须要对数据的类型进行判断,常见的判断办法有:

  • typeof
  • Object.prototype.toString.call
  • instanceof
  • constructor

如果是根本数据类型 (number,string,boolean,null,undefined) 时,能够间接将值进行返回;

这里要提到 null 和 undefined 的类型校验,可参看视频内容。

如果是函数类型 (function) 时,能够间接将该函数返回,因为函数个别以调用为主,将函数转为字符串复制一遍再返回仍旧是这个函数;

如果是内置对象实例,则依据其类新建对应的对象返回即可;

例如:RegExp,Date 等

如果是数组或对象等援用类型,则依据其构造函数新建对应的值返回即可。

({}).constructor //[Function: Object]

([]).constructor //[Function: Array]

依据其构造函数能够间接 new 新值,创立新的值后,新值与旧值齐全无关,这时通过循环旧值的索引或键,将值顺次赋值到新值下来即可。

附办法源码:

function deepClone(value) {if (value == undefined) return value;
    if (typeof value !== 'object') return value; 
    if (value instanceof RegExp) return new RegExp(value);
    if (value instanceof Date) return new Date(value);

    let instance = new value.constructor;
    for (let key in value) {if (value.hasOwnProperty(key)) {    // 只拷贝公有属性
            instance[key] = deepClone(value[key]);
        }
    }
    return instance;
}

正文完
 0