前端面试系列:深拷贝与浅拷贝

28 阅读1分钟

深拷贝和浅拷贝是针对引用类型(对象类型跟数组类型)而言的。其中,浅拷贝,会创建一个新的对象,对原对象的属性进行拷贝,如果原对象中的属性值是基本数据类型,则直接拷贝属性值;如果属性值是引用类型,拷贝的则是指向这个属性值的地址。而深拷贝则是把原对象完整地拷贝一份出来,放到新的内存中。 总而言之,对于浅拷贝,如果属性值是引用类型,则新旧对象都可以对其进行修改。对于深拷贝而言,新旧对象则是独立的,互不影响。

实现过程

浅拷贝

// 判断值是否是对象类型
function isObject (val) {
    if (val === null) {
        return false;
    }
    const type = typeof val;
    return type === 'object' || type === 'function';
}

function shallowCopy(origin) {
    // 不是引用类型,直接返回值
    if (!isObject(origin)) return origin;

    const temp = Array.isArray(origin) ? [] : {};

    // 浅拷贝,getOwnPropertySymbols是获取对象中Symbol类型的key
    const keys = [...Object.keys(origin), ...Object.getOwnPropertySymbols(origin)];
    keys.forEach(key => {
        temp[key] = origin[key];
    })

    return temp
}

深拷贝

function deepCopy(origin) {
    const visited = new WeakMap();

    function base(target) {
        if (!isObject(target)) return target;

        // 处理循环引用,如: let a={}, b = {}; a.b=b; b.a=a; a引用b,b引用a
        if (visited.get(target)) {
            // target对象如果已经被访问过,直接返回值
            return visited.get(target)
        }

        const result = Array.isArray(target) ? [] : {};
        // 标识target对象已经被访问过了
        visited.set(target, result)

        const keys = [...Object.keys(target), ...Object.getOwnPropertySymbols(target)];
        keys.forEach(key => {
            const val = target[key];
            if (isObject(val)) {
                result[key] = base(val);
            } else {
                result[key] = val;
            }
        })

        return result;
    }

    return base(origin)
}

测试

const test = {name: 'test', other: {age: '18'}};
const r1 = shallowCopy(test);
const r2 = deepCopy(test);