这个动态合并两个对象的解决方案可以更简单吗?

问题描述

如果我有这个 root 对象:

const root = {
    list: {
        first: false,second: false,third: false,forth: false
    }
};

并且想要创建一个具有相同结构但更改单个变量的新对象。我可以通过以下方式做到这一点:

const result = {
    ...root,list: {
        ...root.list,first: true
    }
}

所以结果将是:

{
  "list": {
    "first": true,"second": false,"third": false,"forth": false
  }
}

一切正常,但我需要以动态方式做同样的事情。假设我传递了 root 对象、需要更新的属性的完整路径 "list.first" 作为字符串一个值。我找到了解决方案:

const merge = require('lodash').merge;

const root = {
    list: {
        first: false,forth: false
    }
};

function createObjectByPathAndValue(path,value) {
    const keys = (path || '').split('.') || [];

    function createObjectByPathAndValue(root,keys,value) {
        if (keys.length === 1) {
            root[keys[0]] = value;
        } else {
            const key = keys.splice(0,1);
            root[key] = createObjectByPathAndValue({},value);
        }
        return root;
    }

    const result = createObjectByPathAndValue({},value);
    return result;
}

const changes = createObjectByPathAndValue('list.first',true);

const result = merge({},root,changes);

console.log(JSON.stringify(result,null,2 ));

但是让我们同意它很麻烦,而且代码太多。我认为我没有使用现代 javascript 的所有可能性,它可以更简单地完成。我说得对吗?

附言必须创建一个新对象,即不允许改变现有对象(我需要它来更新 React 的状态)

解决方法

您可以深度克隆对象并更改值:

const {cloneDeep,toPath,set} = require('lodash');

const root = {
    list: {
        first: false,second: false,third: false,forth: false
    }
};

const result = cloneDeep(root);
set(result,toPath('list.first'),true);

console.log(JSON.stringify(result,null,2));

这是一个例子(jsfiddle 不支持 require):

const root = {
    list: {
        first: false,forth: false
    }
};

const result = _.cloneDeep(root);
_.set(result,_.toPath('list.first'),2));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

,

我最终使用了 set 包中的 lodash/fn/set 函数,如 this answer

中所述
const setFp = require('lodash/fp/set');

const root = {
    list: {
        first: false,forth: false
    }
};

const newRoot = setFp(`list.first`,true,root); //a new object will be created

阅读有关 lodash/fp 软件包的更多信息。