20200113 用proxy写一个merge函数??

365 阅读1分钟

这几天有用到了merge,总是感觉一直在递归,所以就想能不能不用呢
然后写了一下,依然递归 🤮 但是这么一写还是感觉有些新鲜的

    const toString = {}.toString;
    const type = (v) => toString.call(v).substring(8).replace(']', '').toLowerCase();
    const isSetValue = (v) => ['string', 'number', 'undefined', 'function', 'null'].includes(type(v));
	
    // 直接合并的值,不对比
    const valueAssign = (targetObj, sourceObj) => {
        if (isSetValue(sourceObj) || isSetValue(targetObj)) {
            return sourceObj === undefined ? targetObj : sourceObj;
        }
    };

    const createProxy = (targetObj, sourceObj) => {
        const v = valueAssign(targetObj, sourceObj);
        if (v) return v;

        return new Proxy(targetObj, {
            set(target, key, value, receiver) {
                const v = valueAssign(target[key], sourceObj[key]);
                if (v) {
                    target[key] = value;
                    return true;
                }

                const t = target[key];
                const s = sourceObj[key];

                const typeT = type(t);
                const typeS = type(s);
				
                // 数组和对象类型才去判断合并
                switch (true) {
                    case typeT === 'array' && typeS === 'array':
                        const tLen = t.length;
                        const sLen = s.length;
                        for (let i = 0, n = Math.max(tLen, sLen); i < n; i++) {
                            target[key][i] = baseDeepMerge(t[i], s[i]);
                        }
                        break;
                    case typeT === 'object' && typeS === 'object':
                        baseDeepMerge(t, s);
                        break;
                    default:
                        target[key] = s;
                        break;
                }

                return true;
            },
        });
    };

    const baseDeepMerge = (targetObj, sourceObj) => {
        const v = valueAssign(targetObj, sourceObj);
        if (v) return v;
        const proxyTarget = createProxy(targetObj, sourceObj);
        // proxy.a = 3;
        Object.assign(proxyTarget, sourceObj);
        return targetObj;
    };

    const deepMerge = (t, ...args) => {
        args.forEach((s) => {
            baseDeepMerge(t, s);
        });
        return t;
    };
    
    // [
    //     1,
    //     5,
    //     {
    //         b: 5,
    //         ccc: 1,
    //         d: 123,
    //     },
    //     {
    //         b: 2,
    //     },
    // ]
    console.log(
        deepMerge(
            [1, { a: 1 }, { b: 2 }], //
            [3, 4, { ccc: 1 }, { b: 2 }], //
            [1, 5, { b: 5, d: 123 }] //
        )
    );