不可变地删除对象中的 属性
Remove a property in an object immutably
我正在使用 Redux。在我的减速器中,我试图从这样的对象中删除 属性:
const state = {
a: '1',
b: '2',
c: {
x: '42',
y: '43'
},
}
我想拥有这样的东西而不必改变原始状态:
const newState = {
a: '1',
b: '2',
c: {
x: '42',
},
}
我试过:
let newState = Object.assign({}, state);
delete newState.c.y
但由于某些原因,它从两个状态中删除了 属性。
可以帮我做吗?
那是因为您正在将 state.c
的值复制到另一个对象。该值是指向另一个 javascript 对象的指针。所以,这两个指针都指向同一个对象。
试试这个:
let newState = Object.assign({}, state);
console.log(newState == state); // false
console.log(newState.c == state.c); // true
newState.c = Object.assign({}, state.c);
console.log(newState.c == state.c); // now it is false
delete newState.c.y;
您还可以对对象进行深拷贝。查看 this question,您会找到最适合您的内容。
我发现像 filter
、map
和 reduce
这样的 ES5 数组方法很有用,因为它们总是 return 新数组或对象。在这种情况下,我将使用 Object.keys
遍历对象,并使用 Array#reduce
将其变回对象。
return Object.assign({}, state, {
c: Object.keys(state.c).reduce((result, key) => {
if (key !== 'y') {
result[key] = state.c[key];
}
return result;
}, {})
});
您可以使用 lodash 库中的 _.omit(object, [paths])
路径可以嵌套,例如:_.omit(object, ['key1.key2.key3'])
这个怎么样:
function removeByKey (myObj, deleteKey) {
return Object.keys(myObj)
.filter(key => key !== deleteKey)
.reduce((result, current) => {
result[current] = myObj[current];
return result;
}, {});
}
它过滤应该删除的键,然后从剩余的键和初始对象构建一个新对象。这个想法是从 Tyler McGinnes 很棒的 reactjs 程序中偷来的。
使用 Immutable.js 很容易:
const newState = state.deleteIn(['c', 'y']);
function dissoc(key, obj) {
let copy = Object.assign({}, obj)
delete copy[key]
return copy
}
此外,如果要查找函数式编程工具包,请查看 Ramda。
您可以使用 Immutability helper 来取消设置属性,在您的情况下:
import update from 'immutability-helper';
const updatedState = update(state, {
c: {
$unset: ['y']
}
});
使用 destructuring assignment 语法怎么样?
const original = {
foo: 'bar',
stack: 'overflow',
};
// If the name of the property to remove is constant
const { stack, ...withoutFirst } = original;
console.log(withoutFirst); // Will be { "foo": "bar" }
// If the name of the property to remove is from a variable
const key = 'stack'
const { [key]: value, ...withoutSecond } = original;
console.log(withoutSecond); // Will be { "foo": "bar" }
// To do a deep removal with property names from variables
const deep = {
foo: 'bar',
c: {
x: 1,
y: 2
}
};
const parentKey = 'c';
const childKey = 'y';
// Remove the 'c' element from original
const { [parentKey]: parentValue, ...noChild } = deep;
// Remove the 'y' from the 'c' element
const { [childKey]: removedValue, ...childWithout } = parentValue;
// Merge back together
const withoutThird = { ...noChild, [parentKey]: childWithout };
console.log(withoutThird); // Will be { "foo": "bar", "c": { "x": 1 } }
我一般用
Object.assign({}, existingState, {propToRemove: undefined})
我意识到这实际上并没有删除 属性 但对于几乎所有目的 1 它在功能上是等效的。它的语法比我认为是一个很好的权衡的替代方案要简单得多。
1如果您使用hasOwnProperty()
,您将需要使用更复杂的解决方案。
正如一些答案中已经暗示的那样,这是因为您正在尝试修改嵌套状态,即。更深一层。一个规范的解决方案是在 x
状态级别添加一个减速器:
const state = {
a: '1',
b: '2',
c: {
x: '42',
y: '43'
},
}
更深层次的减速器
let newDeepState = Object.assign({}, state.c);
delete newDeepState.y;
原级减速器
let newState = Object.assign({}, state, {c: newDeepState});
我用这个模式
const newState = Object.assign({}, state);
delete newState.show;
return newState;
但在书中我看到了另一种模式
return Object.assign({}, state, { name: undefined } )
只需使用 ES6 对象解构特性
const state = {
c: {
x: '42',
y: '43'
},
}
const { c: { y, ...c } } = state // generates a new 'c' without 'y'
console.log({...state, c }) // put the new c on a new state
实用程序 ;))
const removeObjectField = (obj, field) => {
// delete filter[selectName]; -> this mutates.
const { [field]: remove, ...rest } = obj;
return rest;
}
动作类型
const MY_Y_REMOVE = 'MY_Y_REMOVE';
动作创作者
const myYRemoveAction = (c, y) => {
const result = removeObjectField(c, y);
return dispatch =>
dispatch({
type: MY_Y_REMOVE,
payload: result
})
}
减速器
export default (state ={}, action) => {
switch (action.type) {
case myActions.MY_Y_REMOVE || :
return { ...state, c: action.payload };
default:
return state;
}
};
您遇到的问题是您没有深度克隆您的初始状态。所以你有一个浅拷贝。
您可以使用展开运算符
const newState = { ...state, c: { ...state.c } };
delete newState.c.y
或遵循相同的代码
let newState = Object.assign({}, state, { c: Object.assign({}, state.c) });
delete newState.c.y
自 2019 年起,另一种选择是使用 Object.fromEntries
方法。它已进入第 4 阶段。
const newC = Object.fromEntries(
Object.entries(state.c).filter(([key]) => key != 'y')
)
const newState = {...state, c: newC}
它的好处在于它可以很好地处理整数键。
这是一个简单的 1-liner,您可以使用它来部分应用要移除的道具。这使得传递给 Array.map
.
变得容易
const removeProp = prop => ({ [prop]: _, ...rest }) => ({ ...rest })
现在你可以这样使用了:
const newArr = oldArr.map(removeProp('deleteMe'))
使用 Object.assign、JSON.parse 和 JSON.stringify
的组合
const obj1 = { a: "a", b: "b" };
const obj2 = { c: "c", a: undefined };
const merged = Object.assign({}, obj1, obj2);
const sanitized = JSON.parse(JSON.stringify(merged));
console.log(sanitized); // -> { b: "b", c: "c" }
我正在使用 Redux。在我的减速器中,我试图从这样的对象中删除 属性:
const state = {
a: '1',
b: '2',
c: {
x: '42',
y: '43'
},
}
我想拥有这样的东西而不必改变原始状态:
const newState = {
a: '1',
b: '2',
c: {
x: '42',
},
}
我试过:
let newState = Object.assign({}, state);
delete newState.c.y
但由于某些原因,它从两个状态中删除了 属性。
可以帮我做吗?
那是因为您正在将 state.c
的值复制到另一个对象。该值是指向另一个 javascript 对象的指针。所以,这两个指针都指向同一个对象。
试试这个:
let newState = Object.assign({}, state);
console.log(newState == state); // false
console.log(newState.c == state.c); // true
newState.c = Object.assign({}, state.c);
console.log(newState.c == state.c); // now it is false
delete newState.c.y;
您还可以对对象进行深拷贝。查看 this question,您会找到最适合您的内容。
我发现像 filter
、map
和 reduce
这样的 ES5 数组方法很有用,因为它们总是 return 新数组或对象。在这种情况下,我将使用 Object.keys
遍历对象,并使用 Array#reduce
将其变回对象。
return Object.assign({}, state, {
c: Object.keys(state.c).reduce((result, key) => {
if (key !== 'y') {
result[key] = state.c[key];
}
return result;
}, {})
});
您可以使用 lodash 库中的 _.omit(object, [paths])
路径可以嵌套,例如:_.omit(object, ['key1.key2.key3'])
这个怎么样:
function removeByKey (myObj, deleteKey) {
return Object.keys(myObj)
.filter(key => key !== deleteKey)
.reduce((result, current) => {
result[current] = myObj[current];
return result;
}, {});
}
它过滤应该删除的键,然后从剩余的键和初始对象构建一个新对象。这个想法是从 Tyler McGinnes 很棒的 reactjs 程序中偷来的。
使用 Immutable.js 很容易:
const newState = state.deleteIn(['c', 'y']);
function dissoc(key, obj) {
let copy = Object.assign({}, obj)
delete copy[key]
return copy
}
此外,如果要查找函数式编程工具包,请查看 Ramda。
您可以使用 Immutability helper 来取消设置属性,在您的情况下:
import update from 'immutability-helper';
const updatedState = update(state, {
c: {
$unset: ['y']
}
});
使用 destructuring assignment 语法怎么样?
const original = {
foo: 'bar',
stack: 'overflow',
};
// If the name of the property to remove is constant
const { stack, ...withoutFirst } = original;
console.log(withoutFirst); // Will be { "foo": "bar" }
// If the name of the property to remove is from a variable
const key = 'stack'
const { [key]: value, ...withoutSecond } = original;
console.log(withoutSecond); // Will be { "foo": "bar" }
// To do a deep removal with property names from variables
const deep = {
foo: 'bar',
c: {
x: 1,
y: 2
}
};
const parentKey = 'c';
const childKey = 'y';
// Remove the 'c' element from original
const { [parentKey]: parentValue, ...noChild } = deep;
// Remove the 'y' from the 'c' element
const { [childKey]: removedValue, ...childWithout } = parentValue;
// Merge back together
const withoutThird = { ...noChild, [parentKey]: childWithout };
console.log(withoutThird); // Will be { "foo": "bar", "c": { "x": 1 } }
我一般用
Object.assign({}, existingState, {propToRemove: undefined})
我意识到这实际上并没有删除 属性 但对于几乎所有目的 1 它在功能上是等效的。它的语法比我认为是一个很好的权衡的替代方案要简单得多。
1如果您使用hasOwnProperty()
,您将需要使用更复杂的解决方案。
正如一些答案中已经暗示的那样,这是因为您正在尝试修改嵌套状态,即。更深一层。一个规范的解决方案是在 x
状态级别添加一个减速器:
const state = {
a: '1',
b: '2',
c: {
x: '42',
y: '43'
},
}
更深层次的减速器
let newDeepState = Object.assign({}, state.c);
delete newDeepState.y;
原级减速器
let newState = Object.assign({}, state, {c: newDeepState});
我用这个模式
const newState = Object.assign({}, state);
delete newState.show;
return newState;
但在书中我看到了另一种模式
return Object.assign({}, state, { name: undefined } )
只需使用 ES6 对象解构特性
const state = {
c: {
x: '42',
y: '43'
},
}
const { c: { y, ...c } } = state // generates a new 'c' without 'y'
console.log({...state, c }) // put the new c on a new state
实用程序 ;))
const removeObjectField = (obj, field) => {
// delete filter[selectName]; -> this mutates.
const { [field]: remove, ...rest } = obj;
return rest;
}
动作类型
const MY_Y_REMOVE = 'MY_Y_REMOVE';
动作创作者
const myYRemoveAction = (c, y) => {
const result = removeObjectField(c, y);
return dispatch =>
dispatch({
type: MY_Y_REMOVE,
payload: result
})
}
减速器
export default (state ={}, action) => {
switch (action.type) {
case myActions.MY_Y_REMOVE || :
return { ...state, c: action.payload };
default:
return state;
}
};
您遇到的问题是您没有深度克隆您的初始状态。所以你有一个浅拷贝。
您可以使用展开运算符
const newState = { ...state, c: { ...state.c } };
delete newState.c.y
或遵循相同的代码
let newState = Object.assign({}, state, { c: Object.assign({}, state.c) });
delete newState.c.y
自 2019 年起,另一种选择是使用 Object.fromEntries
方法。它已进入第 4 阶段。
const newC = Object.fromEntries(
Object.entries(state.c).filter(([key]) => key != 'y')
)
const newState = {...state, c: newC}
它的好处在于它可以很好地处理整数键。
这是一个简单的 1-liner,您可以使用它来部分应用要移除的道具。这使得传递给 Array.map
.
const removeProp = prop => ({ [prop]: _, ...rest }) => ({ ...rest })
现在你可以这样使用了:
const newArr = oldArr.map(removeProp('deleteMe'))
使用 Object.assign、JSON.parse 和 JSON.stringify
的组合const obj1 = { a: "a", b: "b" };
const obj2 = { c: "c", a: undefined };
const merged = Object.assign({}, obj1, obj2);
const sanitized = JSON.parse(JSON.stringify(merged));
console.log(sanitized); // -> { b: "b", c: "c" }