在 JavaScript 的开发过程当中,你可能会遇到合并两个对象的属性的需求。其实在 JS 中合并两个对象的属性也是常见的操作。

本文将为你介绍在 JavaScript 中合并对象属性的多种方法,方便你在 js 中合并两个对象的属性。

对象属性合并的浅拷贝与深拷贝之分

对象属性的合并分为浅拷贝与深拷贝:

  • 浅拷贝:只合并两个对象的第一层的属性,也就是顶层的属性,当顶层属性是对象时,会对属性对象进行引用,这一点一定要注意。
  • 深拷贝:递归的合并两个对象的所有层级的属性,即:完全合并两个对象的属性。

实现浅拷贝的方法

使用 Object.assign() 合并顶层属性

Object.assign() 方法是在 ES6 中新引入的特性,它能够实现合并两个对象的顶层属性,也就是浅拷贝。

使用 Object.assign() 合并顶层属性的示例:

const target = { a: 1, b: 2 };
const source = { b: 3, c: 4 };

const merged = Object.assign(target, source);
console.log(merged);

输出内容为:

Object { a: 1, b: 3, c: 4 }

函数解释:

  • 把其他参数的属性合并到第一个参数当中
  • 当属性名时,后面对象的属性覆盖前面的
  • 可以合并多个对象的属性

合并多个对象属性的示例:

const merged = Object.assign(target, source1, source2);

使用扩展运算符 (...)实现浅拷贝

在 ES6 中新引入了扩展运算符,扩展运算符的作用,如果变量为对象,则会把对象的属性提取出来,作为当前对象的属性:

const merged = { ...obj1, ...obj2 };

它与 Object.assign() 相比语法上会更加的简单,同时它不会调用 setter() 方法,也可以直接添加属性。

使用扩展运算符 (...)提取对象属性和添加新属性的示例:

const merged = {
  ...obj1,
  ...obj2,
  name: 'wang'
};

实现深拷贝合并对象属性的方法

递归深拷贝合并

自定义一个实现深拷贝的函数,在该函数内容同时可以处理Symbol属性。函数的定义过程已经添加了注释,该函数可以拿来直接使用。

function deepMerge(target, source) {
    // 处理循环引用
    const seen = new WeakMap();
    // 定义内部递归合并函数
    function merge(t, s) {
        // 基本类型或 null,直接返回源对象
        if (s === null || typeof s !== "object") {
            return s;
        }
        // 检查循环引用
        if (seen.has(s)) {
            return seen.get(s);
        }
        // 处理数组
        if (Array.isArray(s)) {
            const copy = [];
            seen.set(s, copy);
            s.forEach((item, index) => {
                copy[index] = merge(Array.isArray(t) ? t[index] : undefined, item);
            });
            return copy;
        }
        // 处理普通对象
        const output = Array.isArray(t) ? [...t] : { ...t };
        seen.set(s, output);
        // 处理 Symbol 属性
        const symbolKeys = Object.getOwnPropertySymbols(s);
        const allKeys = [...Object.keys(s), ...symbolKeys];
        // 递归合并
        allKeys.forEach((key) => {
            output[key] = merge(t[key], s[key]);
        });
        return output;
    }
    return merge(target, source);
}

// 使用示例
const target = { a: 1, b: { c: 2 } };
const source = { b: { d: 3, c: [1, 2, 3] }, e: 4 };

const merged = deepMerge(target, source);
console.log(merged);

输出内容为:

Object { a: 1, b: Object { c: Array [1, 2, 3], d: 3 }, e: 4 }

使用第三方库提供的方法

可以使用 Lodash 提供 merge() 方法实现两个对象属性的深拷贝:

import { merge } from 'lodash';

// 基本深合并
const target = { a: 1, b: { c: 2 } };
const source = { b: { d: 3, c: [1, 2, 3] }, e: 4 };

// 基本深合并
const merged = merge(target, source);
console.log(merged)

// 在浏览器端加载lodash库后,使用如下方式引用函数
const merged = _.merge(target, source);

输出内容为:

Object { a: 1, b: Object { c: Array [1, 2, 3], d: 3 }, e: 4 }

常用的可用的其他深拷贝的第三方库有 deepmergeimmer

总结

在本文中介绍了合并两个对象属性的两种方式:浅拷贝和深拷贝;实现浅拷贝的方法有使用扩展运算符 ...Object.assign() 方法;实现深拷贝的方法有自定义函数和使用第三方库 Lodash 提供的函数,希望本文能够对你有所帮助。