从对象中删除值而不发生突变
Remove value from object without mutation
在不改变原始对象的情况下从对象的特定键处删除值的好方法是什么?
我想做这样的事情:
let o = {firstname: 'Jane', lastname: 'Doe'};
let o2 = doSomething(o, 'lastname');
console.log(o.lastname); // 'Doe'
console.log(o2.lastname); // undefined
我知道有很多用于此类任务的不变性库,但我想在没有库的情况下离开。但要做到这一点,一个要求是有一个简单而简短的方法,可以在整个代码中使用,而不需要将方法抽象为实用函数。
例如为了添加一个值,我执行以下操作:
let o2 = {...o1, age: 31};
这很短,容易记住,不需要实用函数。
是否有类似这样的删除值的方法? ES6 非常受欢迎。
非常感谢!
更新:
您可以使用棘手的 Destructuring assignment:
从对象中删除 属性
const doSomething = (obj, prop) => {
let {[prop]: omit, ...res} = obj
return res
}
不过,如果 属性 您要删除的名称是静态的,那么您可以使用简单的一行代码将其删除:
let {lastname, ...o2} = o
最简单的方法就是或者你可以在改变它之前克隆你的对象:
const doSomething = (obj, prop) => {
let res = Object.assign({}, obj)
delete res[prop]
return res
}
或者您可以使用 omit
function from lodash
utility library:
let o2 = _.omit(o, 'lastname')
它作为 lodash package, or as a standalone lodash.omit 包的一部分提供。
如上评论中所建议,如果您想扩展它以从 object
中删除多个项目,我喜欢使用 filter
。和 reduce
例如
const o = {
"firstname": "Jane",
"lastname": "Doe",
"middlename": "Kate",
"age": 23,
"_id": "599ad9f8ebe5183011f70835",
"index": 0,
"guid": "1dbb6a4e-f82d-4e32-bb4c-15ed783c70ca",
"isActive": true,
"balance": ",510.89",
"picture": "http://placehold.it/32x32",
"eyeColor": "green",
"registered": "2014-08-17T09:21:18 -10:00",
"tags": [
"consequat",
"ut",
"qui",
"nulla",
"do",
"sunt",
"anim"
]
};
const removeItems = ['balance', 'picture', 'tags']
console.log(formatObj(o, removeItems))
function formatObj(obj, removeItems) {
return {
...Object.keys(obj)
.filter(item => !isInArray(item, removeItems))
.reduce((newObj, item) => {
return {
...newObj, [item]: obj[item]
}
}, {})
}
}
function isInArray(value, array) {
return array.indexOf(value) > -1;
}
一行解决方案
const removeKey = (key, {[key]: _, ...rest}) => rest;
解释:
这是删除特定键的通用箭头函数。第一个参数是要删除的键的名称,第二个参数是要从中删除键的对象。请注意,通过重组它,我们生成了策划结果,然后 return 它。
示例:
let example = {
first:"frefrze",
second:"gergerge",
third: "gfgfg"
}
console.log(removeKey('third', example))
/*
Object {
first: "frefrze",
second: "gergerge"
}
*/
使用 ES7 对象解构:
const myObject = {
a: 1,
b: 2,
c: 3
};
const { a, ...noA } = myObject;
console.log(noA); // => { b: 2, c: 3 }
使用 lodash cloneDeep 并删除
(注意:lodash 克隆可以代替浅对象使用)
const obj = {a: 1, b: 2, c: 3}
const unwantedKey = 'a'
const _ = require('lodash')
const objCopy = _.cloneDeep(obj)
delete objCopy[unwantedKey]
// objCopy = {b: 2, c: 3}
添加一些香料来提高性能。检查下面的线程
https://github.com/googleapis/google-api-nodejs-client/issues/375
The use of the delete operator has performance negative effects for
the V8 hidden classes pattern. In general it's recommended do not use
it.
Alternatively, to remove object own enumerable properties, we could
create a new object copy without those properties (example using
lodash):
_.omit(o, 'prop', 'prop2')
Or even define the property value to null or undefined (which is
implicitly ignored when serializing to JSON):
o.prop = undefined
你也可以使用破坏的方式
const {remov1, remov2, ...new} = old;
old = new;
还有一个更实际的例子:
this._volumes[this._minCandle] = undefined;
{
const {[this._minCandle]: remove, ...rest} = this._volumes;
this._volumes = rest;
}
如您所见,您可以对动态名称使用 [somePropsVarForDynamicName]: scopeVarName
语法。你可以把所有的都放在括号里(新块),这样剩下的就会在它之后被垃圾收集。
这里有一个测试:
执行:
或者我们可以使用像
这样的函数
function deleteProps(obj, props) {
if (!Array.isArray(props)) props = [props];
return Object.keys(obj).reduce((newObj, prop) => {
if (!props.includes(prop)) {
newObj[prop] = obj[prop];
}
return newObj;
}, {});
}
打字稿
function deleteProps(obj: Object, props: string[]) {
if (!Array.isArray(props)) props = [props];
return Object.keys(obj).reduce((newObj, prop) => {
if (!props.includes(prop)) {
newObj[prop] = obj[prop];
}
return newObj;
}, {});
}
用法:
let a = {propH: 'hi', propB: 'bye', propO: 'ok'};
a = deleteProps(a, 'propB');
// or
a = deleteProps(a, ['propB', 'propO']);
这样就创建了一个新对象。并保持对象的快速属性。这可能很重要或很重要。如果映射和对象会被多次访问
同时关联 undefined
也是一个不错的选择。什么时候买得起。对于键,您也可以检查值。例如,要获取所有活动密钥,您可以执行以下操作:
const allActiveKeys = Object.keys(myObj).filter(k => myObj[k] !== undefined);
//or
const allActiveKeys = Object.keys(myObj).filter(k => myObj[k]); // if any false evaluated value is to be stripped.
Undefined 不适合大列表。或随着时间的推移而发展,有许多 props 进来。因为内存使用量将不断增长并且永远不会被清理。所以这取决于使用情况。并且只创建一个新对象似乎是个好方法。
然后 Premature optimization is the root of all evil
将启动。因此您需要注意权衡。需要什么不需要什么。
关于来自 lodash_.omit() 的注意事项
它已从版本 5 中删除。您无法在存储库中找到它。这里有一个讨论它的问题。
https://github.com/lodash/lodash/issues/2930
v8
你可以看看这是一本不错的读物https://v8.dev/blog/fast-properties
对于我的代码,我想要 map() 的 return 值的简短版本,但 multiline/mutli 操作解决方案是 "ugly"。关键特征是旧的 void(0)
解析为 undefined
。
let o2 = {...o, age: 31, lastname: void(0)};
属性留在对象中:
console.log(o2) // {firstname: "Jane", lastname: undefined, age: 31}
但是传输框架帮我解决了问题 (b.c.stringify):
console.log(JSON.stringify(o2)) // {"firstname":"Jane","age":31}
如果您尝试解构,我对来自 ESLint 规则标准的已接受答案的问题:
const { notNeeded, alsoNotNeeded, ...rest } = { ...ogObject };
2 个新变量,notNeeded
和 alsoNotNeeded
可能会引发警告或错误,具体取决于您的设置,因为它们现在未被使用。那么,如果未使用,为什么要创建新变量?
我认为你需要真正使用 delete
功能。
我为我写了一个关于问题的大函数。该函数将 props 的所有值(不是它本身,只有值)、数组等清除为多维。
注意:函数清除数组中的元素,数组变成空数组。也许可以将此案例添加为可选功能。
https://gist.github.com/semihkeskindev/d979b169e4ee157503a76b06573ae868
function clearAllValues(data, byTypeOf = false) {
let clearValuesTypeOf = {
boolean: false,
number: 0,
string: '',
}
// clears array if data is array
if (Array.isArray(data)) {
data = [];
} else if (typeof data === 'object' && data !== null) {
// loops object if data is object
Object.keys(data).forEach((key, index) => {
// clears array if property value is array
if (Array.isArray(data[key])) {
data[key] = [];
} else if (typeof data[key] === 'object' && data !== null) {
data[key] = this.clearAllValues(data[key], byTypeOf);
} else {
// clears value by typeof value if second parameter is true
if (byTypeOf) {
data[key] = clearValuesTypeOf[typeof data[key]];
} else {
// value changes as null if second parameter is false
data[key] = null;
}
}
});
} else {
if (byTypeOf) {
data = clearValuesTypeOf[typeof data];
} else {
data = null;
}
}
return data;
}
这是一个清除所有值而不删除道具的例子
let object = {
name: 'Semih',
lastname: 'Keskin',
brothers: [
{
name: 'Melih Kayra',
age: 9,
}
],
sisters: [],
hobbies: {
cycling: true,
listeningMusic: true,
running: false,
}
}
console.log(object);
// output before changed: {"name":"Semih","lastname":"Keskin","brothers":[{"name":"Melih Kayra","age":9}],"sisters":[],"hobbies":{"cycling":true,"listeningMusic":true,"running":false}}
let clearObject = clearAllValues(object);
console.log(clearObject);
// output after changed: {"name":null,"lastname":null,"brothers":[],"sisters":[],"hobbies":{"cycling":null,"listeningMusic":null,"running":null}}
let clearObject2 = clearAllValues(object);
console.log(clearObject2);
// output after changed by typeof: {"name":"","lastname":"","brothers":[],"sisters":[],"hobbies":{"cycling":false,"listeningMusic":false,"running":false}}
export function deleteKeyFromObject(obj, key) {
return Object.fromEntries(Object.entries(obj).filter(el => el[0] !== key))
}
在不改变原始对象的情况下从对象的特定键处删除值的好方法是什么?
我想做这样的事情:
let o = {firstname: 'Jane', lastname: 'Doe'};
let o2 = doSomething(o, 'lastname');
console.log(o.lastname); // 'Doe'
console.log(o2.lastname); // undefined
我知道有很多用于此类任务的不变性库,但我想在没有库的情况下离开。但要做到这一点,一个要求是有一个简单而简短的方法,可以在整个代码中使用,而不需要将方法抽象为实用函数。
例如为了添加一个值,我执行以下操作:
let o2 = {...o1, age: 31};
这很短,容易记住,不需要实用函数。
是否有类似这样的删除值的方法? ES6 非常受欢迎。
非常感谢!
更新:
您可以使用棘手的 Destructuring assignment:
从对象中删除 属性const doSomething = (obj, prop) => {
let {[prop]: omit, ...res} = obj
return res
}
不过,如果 属性 您要删除的名称是静态的,那么您可以使用简单的一行代码将其删除:
let {lastname, ...o2} = o
最简单的方法就是或者你可以在改变它之前克隆你的对象:
const doSomething = (obj, prop) => {
let res = Object.assign({}, obj)
delete res[prop]
return res
}
或者您可以使用 omit
function from lodash
utility library:
let o2 = _.omit(o, 'lastname')
它作为 lodash package, or as a standalone lodash.omit 包的一部分提供。
如上评论中所建议,如果您想扩展它以从 object
中删除多个项目,我喜欢使用 filter
。和 reduce
例如
const o = {
"firstname": "Jane",
"lastname": "Doe",
"middlename": "Kate",
"age": 23,
"_id": "599ad9f8ebe5183011f70835",
"index": 0,
"guid": "1dbb6a4e-f82d-4e32-bb4c-15ed783c70ca",
"isActive": true,
"balance": ",510.89",
"picture": "http://placehold.it/32x32",
"eyeColor": "green",
"registered": "2014-08-17T09:21:18 -10:00",
"tags": [
"consequat",
"ut",
"qui",
"nulla",
"do",
"sunt",
"anim"
]
};
const removeItems = ['balance', 'picture', 'tags']
console.log(formatObj(o, removeItems))
function formatObj(obj, removeItems) {
return {
...Object.keys(obj)
.filter(item => !isInArray(item, removeItems))
.reduce((newObj, item) => {
return {
...newObj, [item]: obj[item]
}
}, {})
}
}
function isInArray(value, array) {
return array.indexOf(value) > -1;
}
一行解决方案
const removeKey = (key, {[key]: _, ...rest}) => rest;
解释:
这是删除特定键的通用箭头函数。第一个参数是要删除的键的名称,第二个参数是要从中删除键的对象。请注意,通过重组它,我们生成了策划结果,然后 return 它。
示例:
let example = {
first:"frefrze",
second:"gergerge",
third: "gfgfg"
}
console.log(removeKey('third', example))
/*
Object {
first: "frefrze",
second: "gergerge"
}
*/
使用 ES7 对象解构:
const myObject = {
a: 1,
b: 2,
c: 3
};
const { a, ...noA } = myObject;
console.log(noA); // => { b: 2, c: 3 }
使用 lodash cloneDeep 并删除
(注意:lodash 克隆可以代替浅对象使用)
const obj = {a: 1, b: 2, c: 3}
const unwantedKey = 'a'
const _ = require('lodash')
const objCopy = _.cloneDeep(obj)
delete objCopy[unwantedKey]
// objCopy = {b: 2, c: 3}
添加一些香料来提高性能。检查下面的线程
https://github.com/googleapis/google-api-nodejs-client/issues/375
The use of the delete operator has performance negative effects for the V8 hidden classes pattern. In general it's recommended do not use it.
Alternatively, to remove object own enumerable properties, we could create a new object copy without those properties (example using lodash):
_.omit(o, 'prop', 'prop2')
Or even define the property value to null or undefined (which is implicitly ignored when serializing to JSON):
o.prop = undefined
你也可以使用破坏的方式
const {remov1, remov2, ...new} = old;
old = new;
还有一个更实际的例子:
this._volumes[this._minCandle] = undefined;
{
const {[this._minCandle]: remove, ...rest} = this._volumes;
this._volumes = rest;
}
如您所见,您可以对动态名称使用 [somePropsVarForDynamicName]: scopeVarName
语法。你可以把所有的都放在括号里(新块),这样剩下的就会在它之后被垃圾收集。
这里有一个测试:
执行:
或者我们可以使用像
这样的函数function deleteProps(obj, props) {
if (!Array.isArray(props)) props = [props];
return Object.keys(obj).reduce((newObj, prop) => {
if (!props.includes(prop)) {
newObj[prop] = obj[prop];
}
return newObj;
}, {});
}
打字稿
function deleteProps(obj: Object, props: string[]) {
if (!Array.isArray(props)) props = [props];
return Object.keys(obj).reduce((newObj, prop) => {
if (!props.includes(prop)) {
newObj[prop] = obj[prop];
}
return newObj;
}, {});
}
用法:
let a = {propH: 'hi', propB: 'bye', propO: 'ok'};
a = deleteProps(a, 'propB');
// or
a = deleteProps(a, ['propB', 'propO']);
这样就创建了一个新对象。并保持对象的快速属性。这可能很重要或很重要。如果映射和对象会被多次访问
同时关联 undefined
也是一个不错的选择。什么时候买得起。对于键,您也可以检查值。例如,要获取所有活动密钥,您可以执行以下操作:
const allActiveKeys = Object.keys(myObj).filter(k => myObj[k] !== undefined);
//or
const allActiveKeys = Object.keys(myObj).filter(k => myObj[k]); // if any false evaluated value is to be stripped.
Undefined 不适合大列表。或随着时间的推移而发展,有许多 props 进来。因为内存使用量将不断增长并且永远不会被清理。所以这取决于使用情况。并且只创建一个新对象似乎是个好方法。
然后 Premature optimization is the root of all evil
将启动。因此您需要注意权衡。需要什么不需要什么。
关于来自 lodash_.omit() 的注意事项
它已从版本 5 中删除。您无法在存储库中找到它。这里有一个讨论它的问题。
https://github.com/lodash/lodash/issues/2930
v8
你可以看看这是一本不错的读物https://v8.dev/blog/fast-properties
对于我的代码,我想要 map() 的 return 值的简短版本,但 multiline/mutli 操作解决方案是 "ugly"。关键特征是旧的 void(0)
解析为 undefined
。
let o2 = {...o, age: 31, lastname: void(0)};
属性留在对象中:
console.log(o2) // {firstname: "Jane", lastname: undefined, age: 31}
但是传输框架帮我解决了问题 (b.c.stringify):
console.log(JSON.stringify(o2)) // {"firstname":"Jane","age":31}
如果您尝试解构,我对来自 ESLint 规则标准的已接受答案的问题:
const { notNeeded, alsoNotNeeded, ...rest } = { ...ogObject };
2 个新变量,notNeeded
和 alsoNotNeeded
可能会引发警告或错误,具体取决于您的设置,因为它们现在未被使用。那么,如果未使用,为什么要创建新变量?
我认为你需要真正使用 delete
功能。
我为我写了一个关于问题的大函数。该函数将 props 的所有值(不是它本身,只有值)、数组等清除为多维。
注意:函数清除数组中的元素,数组变成空数组。也许可以将此案例添加为可选功能。
https://gist.github.com/semihkeskindev/d979b169e4ee157503a76b06573ae868
function clearAllValues(data, byTypeOf = false) {
let clearValuesTypeOf = {
boolean: false,
number: 0,
string: '',
}
// clears array if data is array
if (Array.isArray(data)) {
data = [];
} else if (typeof data === 'object' && data !== null) {
// loops object if data is object
Object.keys(data).forEach((key, index) => {
// clears array if property value is array
if (Array.isArray(data[key])) {
data[key] = [];
} else if (typeof data[key] === 'object' && data !== null) {
data[key] = this.clearAllValues(data[key], byTypeOf);
} else {
// clears value by typeof value if second parameter is true
if (byTypeOf) {
data[key] = clearValuesTypeOf[typeof data[key]];
} else {
// value changes as null if second parameter is false
data[key] = null;
}
}
});
} else {
if (byTypeOf) {
data = clearValuesTypeOf[typeof data];
} else {
data = null;
}
}
return data;
}
这是一个清除所有值而不删除道具的例子
let object = {
name: 'Semih',
lastname: 'Keskin',
brothers: [
{
name: 'Melih Kayra',
age: 9,
}
],
sisters: [],
hobbies: {
cycling: true,
listeningMusic: true,
running: false,
}
}
console.log(object);
// output before changed: {"name":"Semih","lastname":"Keskin","brothers":[{"name":"Melih Kayra","age":9}],"sisters":[],"hobbies":{"cycling":true,"listeningMusic":true,"running":false}}
let clearObject = clearAllValues(object);
console.log(clearObject);
// output after changed: {"name":null,"lastname":null,"brothers":[],"sisters":[],"hobbies":{"cycling":null,"listeningMusic":null,"running":null}}
let clearObject2 = clearAllValues(object);
console.log(clearObject2);
// output after changed by typeof: {"name":"","lastname":"","brothers":[],"sisters":[],"hobbies":{"cycling":false,"listeningMusic":false,"running":false}}
export function deleteKeyFromObject(obj, key) {
return Object.fromEntries(Object.entries(obj).filter(el => el[0] !== key))
}