使用 Lodash 删除对象属性

我必须删除不需要的对象属性,不符合我的模型。我如何实现它与 Lodash?

我的模式是:

var model = {
fname: null,
lname: null
}

在发送到服务器之前,我的控制器输出将是:

var credentials = {
fname: "xyz",
lname: "abc",
age: 23
}

我知道我可以利用

delete credentials.age

但是如果我有很多不想要的属性呢? 我可以用 Lodash 来实现吗?

192955 次浏览

Get a list of properties from model using _.keys(), and use _.pick() to extract the properties from credentials to a new object:

var model = {
fname:null,
lname:null
};


var credentials = {
fname:"xyz",
lname:"abc",
age:23
};


var result = _.pick(credentials, _.keys(model));


console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>

If you don't want to use Lodash, you can use Object.keys(), and Array.prototype.reduce():

var model = {
fname:null,
lname:null
};


var credentials = {
fname:"xyz",
lname:"abc",
age:23
};


var result = Object.keys(model).reduce(function(obj, key) {
obj[key] = credentials[key];
return obj;
}, {});


console.log(result);

You can easily do this using _.pick:

var model = {
fname: null,
lname: null
};


var credentials = {
fname: 'abc',
lname: 'xyz',
age: 2
};


var result = _.pick(credentials, _.keys(model));




console.log('result =', result);
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>

But you can simply use pure JavaScript (specially if you use ECMAScript 6), like this:

const model = {
fname: null,
lname: null
};


const credentials = {
fname: 'abc',
lname: 'xyz',
age: 2
};


const newModel = {};


Object.keys(model).forEach(key => newModel[key] = credentials[key]);


console.log('newModel =', newModel);

You can approach it from either an "allow list" or a "block list" way:

// Block list
// Remove the values you don't want
var result = _.omit(credentials, ['age']);


// Allow list
// Only allow certain values
var result = _.pick(credentials, ['fname', 'lname']);

If it's reusable business logic, you can partial it out as well:

// Partial out a "block list" version
var clean = _.partial(_.omit, _, ['age']);


// and later
var result = clean(credentials);

Note that Lodash 5 will drop support for omit

A similar approach can be achieved without Lodash:

const transform = (obj, predicate) => {
return Object.keys(obj).reduce((memo, key) => {
if(predicate(obj[key], key)) {
memo[key] = obj[key]
}
return memo
}, {})
}


const omit = (obj, items) => transform(obj, (value, key) => !items.includes(key))


const pick = (obj, items) => transform(obj, (value, key) => items.includes(key))


// Partials
// Lazy clean
const cleanL = (obj) => omit(obj, ['age'])


// Guarded clean
const cleanG = (obj) => pick(obj, ['fname', 'lname'])




// "App"
const credentials = {
fname:"xyz",
lname:"abc",
age:23
}


const omitted = omit(credentials, ['age'])
const picked = pick(credentials, ['age'])
const cleanedL = cleanL(credentials)
const cleanedG = cleanG(credentials)

Here I have used omit() for the respective 'key' which you want to remove... by using the Lodash library:

var credentials = [{
fname: "xyz",
lname: "abc",
age: 23
}]


let result = _.map(credentials, object => {
return _.omit(object, ['fname', 'lname'])
})


console.log('result', result)

To select (or remove) object properties that satisfy a given condition deeply, you can use something like this:

function pickByDeep(object, condition, arraysToo=false) {
return _.transform(object, (acc, val, key) => {
if (_.isPlainObject(val) || arraysToo && _.isArray(val)) {
acc[key] = pickByDeep(val, condition, arraysToo);
} else if (condition(val, key, object)) {
acc[key] = val;
}
});
}

https://codepen.io/aercolino/pen/MWgjyjm

This is my solution to deep remove empty properties with Lodash:

const compactDeep = obj => {
const emptyFields = [];


function calculateEmpty(prefix, source) {
_.each(source, (val, key) => {
if (_.isObject(val) && !_.isEmpty(val)) {
calculateEmpty(`${prefix}${key}.`, val);
} else if ((!_.isBoolean(val) && !_.isNumber(val) && !val) || (_.isObject(val) && _.isEmpty(val))) {
emptyFields.push(`${prefix}${key}`);
}
});
}


calculateEmpty('', obj);


return _.omit(obj, emptyFields);
};

You can use _.omit() for emitting the key from a JSON array if you have fewer objects:

_.forEach(data, (d) => {
_.omit(d, ['keyToEmit1', 'keyToEmit2'])
});

If you have more objects, you can use the reverse of it which is _.pick():

_.forEach(data, (d) => {
_.pick(d, ['keyToPick1', 'keyToPick2'])
});

Lodash unset is suitable for removing a few unwanted keys.

const myObj = {
keyOne: "hello",
keyTwo: "world"
}


unset(myObj, "keyTwo");


console.log(myObj); /// myObj = { keyOne: "hello" }

For array of objects

model = _.filter(model, a => {
if (!a.age) { return a }
})

Recursively removing paths.

I just needed something similar, not removing just keys, but keys by with paths recursively.

Thought I'd share.

Simple readable example, no dependencies

/**
* Removes path from an object recursively.
* A full path to the key is not required.
* The original object is not modified.
*
* Example:
*   const original = { a: { b: { c: 'value' } }, c: 'value'  }
*
*   omitPathRecursively(original, 'a') // outputs: { c: 'value' }
*   omitPathRecursively(original, 'c') // outputs: { a: { b: {} } }
*   omitPathRecursively(original, 'b.c') // { a: { b: {} }, c: 'value' }
*/
export const omitPathRecursively = (original, path, depth = 1) => {
const segments = path.split('.')
const final = depth === segments.length


return JSON.parse(
JSON.stringify(original, (key, value) => {
const match = key === segments[depth - 1]


if (!match) return value
if (!final) return omitPathRecursively(value, path, depth + 1)
return undefined
})
)
}

Working example: https://jsfiddle.net/webbertakken/60thvguc/1/

While looking for a solution that would work for both arrays and objects, I didn't find one and so I created it.

/**
* Recursively ignore keys from array or object
*/
const ignoreKeysRecursively = (obj, keys = []) => {
const keyIsToIgnore = (key) => {
return keys.map((a) => a.toLowerCase()).includes(key)
}


const serializeObject = (item) => {
return Object.fromEntries(
Object.entries(item)
.filter(([key, value]) => key && value)
.reduce((prev, curr, currIndex) => {
if (!keyIsToIgnore(curr[0]))
prev[currIndex] =
[
curr[0],
// serialize array
Array.isArray(curr[1])
? // eslint-disable-next-line
serializeArray(curr[1])
: // serialize object
!Array.isArray(curr[1]) && typeof curr[1] === 'object'
? serializeObject(curr[1])
: curr[1],
] || []
return prev
}, []),
)
}


const serializeArray = (item) => {
const serialized = []
for (const entry of item) {
if (typeof entry === 'string') serialized.push(entry)
if (typeof entry === 'object' && !Array.isArray(entry)) serialized.push(serializeObject(entry))
if (Array.isArray(entry)) serialized.push(serializeArray(entry))
}
return serialized
}


if (Array.isArray(obj)) return serializeArray(obj)
return serializeObject(obj)
}


// usage
const refObject = [{name: "Jessica", password: "ygd6g46"}]
// ignore password
const obj = ignoreKeysRecursively(refObject, ["password"])
// expects returned array to only have name attribute
console.log(obj)