使用另一个对象的值递归更新 JavaScript 对象
Update a JavaScript object recursively using values from another object
我想向嵌套的 JavaScript 对象添加一些数据,但是我不知道对象树中已经存在多少。如果该结构不存在,我想添加该结构,但如果它在那里标记有一些其他默认数据,我也想保留相同的信息。
理想情况下,我不想为此使用第三方库。
在我的示例中,我有以下对象结构,将有这些可用的无限组合,因此如果它尚不存在,则需要为我生成该结构。
{
level1: {
level2: {
level3: {
property1: 'test'
}
}
}
}
我希望能够为其提供一些值,创建结构 - 如果存在结构,则添加一些默认值,如果不存在,则使用默认值创建结构。
我有下面的,它可以完成工作,但我觉得它很乱,我想知道是否有更好的方法来实现它?
const updateNestedObject = (obj, level1, level2, level3, defaultProps) => {
if (obj && obj[level1] && obj[level1][level2] && obj[level1][level2][level3]) {
obj[level1][level2][level3] = { ...defaultProps, ...obj[level1][level2][level3] }
} else if (obj && obj[level1] && obj[level1][level2] && !obj[level1][level2][level3]) {
obj[level1][level2][level3] = defaultProps
} else if (obj && obj[level1] && !obj[level1][level2]) {
obj[level1][level2] = { [level3]: defaultProps }
} else if (obj && !obj[level1]) {
obj[level1] = { [level2]: { [level3]: defaultProps } }
} else {
obj = { [level1]: { [level2]: { [level3]: defaultProps } } }
}
return obj
}
你可以做这样的事情,在键上循环并逐层遍历对象。每个循环我们都将一个外部变量 - level
- 设置为当前变量,因此我们不必使用之前的键来达到当前级别。即,我们避免必须做 obj[ level1 ][ level2 ][ level3 ] = ...
,相反,我们可以做 level = ...
这样的话,我觉得还是传一个参数比较好keys
,就是一个数组。有了这个,您就不会仅限于 3 个嵌套键,而是可以传递任何您想要的数字。
const updateNestedObject = ( obj, keys, defaultProps ) => {
let level = obj;
for ( let i = 0; i <= keys.length-1; i++ ) {
let key = keys[ i ];
if ( i === keys.length-1 ) {
level[ key ] = { ...defaultProps };
return;
}
if ( !level[ key ] ) {
level[ key ] = {};
}
level = level[ key ];
}
};
const object = {};
updateNestedObject( object, [ "foo", "bar", "baz" ], { property: "test" } )
console.log( object );
const object2 = { foo: { bar: {} } };
updateNestedObject( object2, [ "foo", "bar", "baz" ], { property: "test" } )
console.log( object2 );
const object3 = { foo: { bar: {} } };
updateNestedObject( object3, [ "foo", "bar" ], { property: "test" } )
console.log( object3 );
请注意,这确实会更改对象 in-place。
这可以通过递归来完成。下面是如何实施它的大纲(未针对所有情况进行测试):
function mergeRecursive(targetObject, sourceObject) {
Object.keys(sourceObject).forEach(function(key) {
if (typeof sourceObject[key] === "object") {
if (targetObject[key] === undefined) {
targetObject[key] = {};
}
mergeRecursive(targetObject[key], sourceObject[key]);
} else {
targetObject[key] = sourceObject[key];
}
});
}
let foo = {
"level1": {
"bar": "baz"
}
};
let bar = {
level1: {
level2: {
level3: {
property1: "test"
}
}
}
};
mergeRecursive(foo, bar);
console.log(foo);
我经常使用的 setPath
function 的一个小变体会以相当直接的方式执行此操作:
const mixDeep = ([p, ...ps]) => (v) => (o) =>
p == undefined ? v : Object .assign (
Array .isArray (o) || Number .isInteger (p) ? [] : {},
{...o, [p]: ps .length ? mixDeep (ps) (v) ((o || {}) [p]) : {...v, ...(o || {}) [p]}},
)
const myFunc =
mixDeep (['level1', 'level2', 'level3']) ({some: 'default', props: 'here'})
console .log (myFunc ({foo: 'bar'}))
console .log (myFunc ({foo: 'bar', level1: {baz: 'qux'}}))
console .log (myFunc ({foo: 'bar', level1: {baz: 'qux', level2: {corge: 'grault'}}}))
console .log (myFunc ({foo: 'bar', level1: {baz: 'qux', level2: {corge: 'grault', level3: {garply: 'waldo'}}}}))
.as-console-wrapper {max-height: 100% !important; top: 0}
setPath
设置 路径上的值,根据需要构建中间节点。 mixDeep
将值混合 到路径末尾的值中,再次构建缺少的任何中间节点。
我想向嵌套的 JavaScript 对象添加一些数据,但是我不知道对象树中已经存在多少。如果该结构不存在,我想添加该结构,但如果它在那里标记有一些其他默认数据,我也想保留相同的信息。
理想情况下,我不想为此使用第三方库。
在我的示例中,我有以下对象结构,将有这些可用的无限组合,因此如果它尚不存在,则需要为我生成该结构。
{
level1: {
level2: {
level3: {
property1: 'test'
}
}
}
}
我希望能够为其提供一些值,创建结构 - 如果存在结构,则添加一些默认值,如果不存在,则使用默认值创建结构。
我有下面的,它可以完成工作,但我觉得它很乱,我想知道是否有更好的方法来实现它?
const updateNestedObject = (obj, level1, level2, level3, defaultProps) => {
if (obj && obj[level1] && obj[level1][level2] && obj[level1][level2][level3]) {
obj[level1][level2][level3] = { ...defaultProps, ...obj[level1][level2][level3] }
} else if (obj && obj[level1] && obj[level1][level2] && !obj[level1][level2][level3]) {
obj[level1][level2][level3] = defaultProps
} else if (obj && obj[level1] && !obj[level1][level2]) {
obj[level1][level2] = { [level3]: defaultProps }
} else if (obj && !obj[level1]) {
obj[level1] = { [level2]: { [level3]: defaultProps } }
} else {
obj = { [level1]: { [level2]: { [level3]: defaultProps } } }
}
return obj
}
你可以做这样的事情,在键上循环并逐层遍历对象。每个循环我们都将一个外部变量 - level
- 设置为当前变量,因此我们不必使用之前的键来达到当前级别。即,我们避免必须做 obj[ level1 ][ level2 ][ level3 ] = ...
,相反,我们可以做 level = ...
这样的话,我觉得还是传一个参数比较好keys
,就是一个数组。有了这个,您就不会仅限于 3 个嵌套键,而是可以传递任何您想要的数字。
const updateNestedObject = ( obj, keys, defaultProps ) => {
let level = obj;
for ( let i = 0; i <= keys.length-1; i++ ) {
let key = keys[ i ];
if ( i === keys.length-1 ) {
level[ key ] = { ...defaultProps };
return;
}
if ( !level[ key ] ) {
level[ key ] = {};
}
level = level[ key ];
}
};
const object = {};
updateNestedObject( object, [ "foo", "bar", "baz" ], { property: "test" } )
console.log( object );
const object2 = { foo: { bar: {} } };
updateNestedObject( object2, [ "foo", "bar", "baz" ], { property: "test" } )
console.log( object2 );
const object3 = { foo: { bar: {} } };
updateNestedObject( object3, [ "foo", "bar" ], { property: "test" } )
console.log( object3 );
请注意,这确实会更改对象 in-place。
这可以通过递归来完成。下面是如何实施它的大纲(未针对所有情况进行测试):
function mergeRecursive(targetObject, sourceObject) {
Object.keys(sourceObject).forEach(function(key) {
if (typeof sourceObject[key] === "object") {
if (targetObject[key] === undefined) {
targetObject[key] = {};
}
mergeRecursive(targetObject[key], sourceObject[key]);
} else {
targetObject[key] = sourceObject[key];
}
});
}
let foo = {
"level1": {
"bar": "baz"
}
};
let bar = {
level1: {
level2: {
level3: {
property1: "test"
}
}
}
};
mergeRecursive(foo, bar);
console.log(foo);
我经常使用的 setPath
function 的一个小变体会以相当直接的方式执行此操作:
const mixDeep = ([p, ...ps]) => (v) => (o) =>
p == undefined ? v : Object .assign (
Array .isArray (o) || Number .isInteger (p) ? [] : {},
{...o, [p]: ps .length ? mixDeep (ps) (v) ((o || {}) [p]) : {...v, ...(o || {}) [p]}},
)
const myFunc =
mixDeep (['level1', 'level2', 'level3']) ({some: 'default', props: 'here'})
console .log (myFunc ({foo: 'bar'}))
console .log (myFunc ({foo: 'bar', level1: {baz: 'qux'}}))
console .log (myFunc ({foo: 'bar', level1: {baz: 'qux', level2: {corge: 'grault'}}}))
console .log (myFunc ({foo: 'bar', level1: {baz: 'qux', level2: {corge: 'grault', level3: {garply: 'waldo'}}}}))
.as-console-wrapper {max-height: 100% !important; top: 0}
setPath
设置 路径上的值,根据需要构建中间节点。 mixDeep
将值混合 到路径末尾的值中,再次构建缺少的任何中间节点。