Object destructuring ({ x, y, …rest }) for whiteli

2019-06-27 16:31发布

问题:

This question already has an answer here:

  • One-liner to take some properties from object in ES 6 10 answers

Using Object rest destructuring is straightforward to blacklist properties of an object, like in the following example:

const original = {
  a: 1,
  b: 2,
  c: 3,
  evil: "evil",
  ugly: "ugly",
};

const { evil, ugly, ...sanitized } = original;

console.log(sanitized);   // prints { a: 1, b: 2, c: 3 }

I wonder if there exists a similar terse way to do the same, but using a white list of properties (in the example: { a, b, c }). Very often, I have to convert a subset of the available properties as JSON, and such a functionality would make the code much more readable and safer.

I found a similar question, but it is not exactly the same problem: Is there a more terse way to map properties of one object to another in ES6/ES2015?

Edit: It is a pity that the next code doesn't work, as it is returning the original object instead of the filtered one.

const sanitized = {a, b, c} = original;     
// sanitized === original

回答1:

For this purpose I use 2 helper functions

export const pickProps = (object, ...props) => (
  props.reduce((a, x) => {
    if (object.hasOwnProperty(x)) a[x] = object[x];
    return a;
  }, {})
);

export const omitProps = (object, ...props) => {
  const no = {...object};
  props.forEach(p => delete no[p]);
  return no;
};

You can also do

const original = {
  a: 1,
  b: 2,
  c: 3,
  evil: "evil",
  ugly: "ugly",
};

const { a, b, c } = original;
const filtered = { a, b, c };


回答2:

I don't think your way to "blacklist" is good, because it unnecessarily assigns original.evil to evil, and original.ugly to ugly.

You can try this approach:

const blacklistFilter = (obj, blacklist) => Object.entries(obj)
  .filter(([key, value]) => !blacklist.includes(key))
  .reduce((obj, [key, value]) => (obj[key] = value, obj), {})

const whitelistFilter = (obj, whitelist) => Object.entries(obj)
  .filter(([key, value]) => whitelist.includes(key))
  .reduce((obj, [key, value]) => (obj[key] = value, obj), {})

const original = {
  a: 1
 ,b: 2
 ,c: 3
 ,evil: 'evil'
 ,ugly: 'ugly'
}

console.log(blacklistFilter(original, ['evil', 'ugly']))
console.log(whitelistFilter(original, ['a', 'b', 'c']))

Object.entries() returns an array of object's keys and corresponding values in format [key, value], the filter() method filters keys based on whether they aren't blacklisted or whether they are whitelisted, and reduce() method converts the [key, value] array back to an object (similar method as in this answer).