如何在 JavaScript 中省略对象的特定属性

有没有一种干净的方法可以返回一个新对象,它省略了原始对象包含的某些属性,而不必使用 loash 之类的属性?

135382 次浏览

If you know the list of the properties that you want preserved as well as omitted, the following "whitelisting" approach should work:

const exampleFilter = ({ keepMe, keepMeToo }) => ({ keepMe, keepMeToo })


console.log(
exampleFilter({
keepMe: 'keepMe',
keepMeToo: 'keepMeToo',
omitMe: 'omitMe',
omitMeToo: 'omitMeToo'
})
)

You can use Object.assign(), delete

var not = ["a", "b"]; // properties to delete from obj object
var o = Object.assign({}, obj);
for (let n of not) delete o[n];

Alternatively

var props = ["c", "d"];
let o = Object.assign({}, ...props.map(prop => ({[prop]:obj[prop]})));
function omitKeys(obj, keys) {
var target = {};


for (var i in obj) {
if (keys.indexOf(i) >= 0) continue;
if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;


target[i] = obj[i];
}


return target;
}

Sure, why not something like:

var original = {
name: 'Rory',
state: 'Bored',
age: '27'
};


var copied = Object.assign({}, original);
delete copied.age;


console.log(copied);

https://jsfiddle.net/4nL08zk4/

One solution, I'm sure many others exist.

const testObj = {
prop1: 'value1',
prop2: 'value2',
prop3: 'value3'
};


const removeProps = (...propsToFilter) => obj => {
return Object.keys(obj)
.filter(key => !propsToFilter.includes(key))
.reduce((newObj, key) => {
newObj[key] = obj[key];
return newObj;
}, {});
};




console.log(removeProps('prop3')(testObj));
console.log(removeProps('prop1', 'prop2')(testObj));

Edit: I always forget about delete...

const testObj = {
prop1: 'value1',
prop2: 'value2',
prop3: 'value3'
};


const removeProps = (...propsToFilter) => obj => {
const newObj = Object.assign({}, obj);
propsToFilter.forEach(key => delete newObj[key]);
return newObj;
};




console.log(removeProps('prop3')(testObj));
console.log(removeProps('prop1', 'prop2')(testObj));

There's the blacklist package on npm which has a very flexible api.

Also a situational trick using the object rest-spread proposal (stage-3).

const {a, b, ...rest} = {a: 1, b: 2, c: 3, d: 4};
a // 1
b // 2
rest // {c: 3, d: 4}

This is often used in react components where you want to use a few properties and pass the rest as props to a <div {...props} /> or similar.

var obj = {
a: 1,
b: 2,
c: 3,
d: {
c: 3,
e: 5
}
};


Object.extract = function(obj, keys, exclude) {
var clone = Object.assign({}, obj);
if (keys && (keys instanceof Array)) {
for (var k in clone) {
var hasKey = keys.indexOf(k) >= 0;
if ((!hasKey && !exclude) || (hasKey && exclude)) {
delete clone[k];
}
}
}
return clone;
};


console.log('Extract specified keys: \n-----------------------');
var clone1 = Object.extract(obj, ['a', 'd']);
console.log(clone1);
console.log('Exclude specified keys: \n-----------------------');
var clone2 = Object.extract(obj, ['a', 'd'], true);
console.log(clone2);

const { bar, baz, ...qux } = foo

Now your object qux has all of the properties of foo except for bar and baz.

If you already use lodash, you may also do omit(obj, ["properties", "to", "omit"]) to get a new Object without the properties provided in the array.

In modern environments you can use this code snippet:

function omit(key, obj) {
const { [key]: omitted, ...rest } = obj;
return rest;
}

Omit and array of keys, using ES7 w/ recursion.

function omit(keys, obj) {
if (!keys.length) return obj
const { [keys.pop()]: omitted, ...rest } = obj;
return omit(keys, rest);
}

This builds on top of @Eddie Cooro answer.

I saw this question and I wanted to remove 1 specific key, not a full method, so here's my suggestion:

const originalObj = {wantedKey: 111, anotherWantedKey: 222, unwantedKey: 1010};
const cleanedObj = Object.assign(originalObj, {unwantedKey: undefined});

A solution that hasn't been mentioned yet:

Omit single

o = {a: 5, b: 6, c: 7}
Object.fromEntries(Object.entries(o).filter(e => e[0] != 'b'))
// Object { a: 5, c: 7 }

Omit multiple

o = {a: 1, b: 2, c: 3, d: 4}
exclude = new Set(['a', 'b'])
Object.fromEntries(Object.entries(o).filter(e => !exclude.has(e[0])))
// Object { c: 3, d: 4 }

The Set above is used because it leads to linearithmic complexity even if the number of elements in exclude is in the same asymptotic equivalence class as the number of elements in o.

No answer seemed to allow nested path specifications using dot notation. Here's a solution for that:

const omit = (obj, keys) => {
if (!keys.length) return obj;
const key = keys.pop();
const parts = key.split(".");
if (parts.length > 1) {
const { [parts[0]]: todo, ...rest } = obj;
return {
...omit(rest, keys),
[parts[0]]: omit(todo, [parts[1]]),
};
}
const { [key]: omitted, ...rest } = obj;
return omit(rest, keys);
};
    

var obj = {
a: 1,
b: 2,
c: 3,
d: {
c: 3,
e: 5
}
};
console.log(omit(obj, ['b', 'd.c']));

const data = { name : 'Micheal', passowrd : 'password', age: '44'}
const dataClean = data.toObject();
delete dataClean.password;
console.log(dataClean);

Building on other answers: if there's not a need for reusability or abstraction this will remove blacklisted properties inline with an IIFE.

(
({
// Properties to remove from `someObject`.
omitMe,
omitMeToo,
// The rest of `someObject`, to keep.
...keep
}) => keep
)(someObject)

Example

const someObject = {
keepMe: 'keepMe',
keepMeToo: 'keepMeToo',
omitMe: 'omitMe',
omitMeToo: 'omitMeToo',
};


console.log(
(
({
omitMe,
omitMeToo,
...keep
}) => keep
)(someObject)
);