Деструктуризация объекта ({x, y, rest}) для внесения в белый список свойств объекта

Использование деструктуризации оставшейся части объекта позволяет легко внести в черный список свойства объект, как в следующем примере:

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 }

Интересно, существует ли аналогичный краткий способ сделать то же самое, но с использованием белого списка свойств (в примере: { a, b, c }). Очень часто мне приходится конвертировать подмножество доступных свойств в JSON, и такой функционал сделал бы код намного читабельнее и безопаснее.

Я нашел аналогичный вопрос, но это не совсем та же проблема: of-one-object-to-other-in-es6-es20">Есть ли более краткий способ сопоставления свойств одного объекта с другим в ES6/ES2015?

Изменить: жаль, что следующий код не работает, так как он возвращает исходный объект вместо отфильтрованного.

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

person Manolo Santos    schedule 25.08.2016    source источник
comment
Вы имеете в виду наличие объекта отдыха только с определенными свойствами? Нет, не за один шаг. Вы могли бы сделать const { a, b } = original; const new = { a, b };, но вы не получите более краткого, чем это.   -  person nils    schedule 25.08.2016
comment
@nils не обязательно в покое. Я хочу знать, существует ли или предлагается идиоматический способ копирования подмножества свойств из белого списка. Я знаю решение, которое вы предложили, но мне бы не хотелось дублировать такие реквизиты.   -  person Manolo Santos    schedule 25.08.2016
comment
Родного решения нет. Однако вы можете использовать функцию _.pick lodash.   -  person nils    schedule 25.08.2016
comment
Предложение так называемой расширенной точечной нотации позволяет вам произнести object.{a, b, c}, выбрать a, b и c из object и создать из них новый объект. Это обсуждалось в списке рассылки es-discuss. См. этот репозиторий github.   -  person    schedule 25.08.2016
comment
@torazaburo отличная работа! Я так понимаю, он еще не готов к транспиляции?   -  person nils    schedule 25.08.2016
comment
К вашему сведению, свойства остатка объекта не являются частью ES 6. В настоящее время это ES предложение на 2 этапе.   -  person Michał Perłakowski    schedule 25.08.2016
comment
Я действительно думаю, что было бы жаль, если бы оператор присваивания когда-либо оценивал что-либо, кроме своего правильного операнда.   -  person Paul    schedule 25.08.2016
comment
@Paulpro Хороший вопрос! Это сбивает с толку. В любом случае транзитивная деструктуризация сама по себе довольно запутанна (например, const { a, b } = { c, d } = { a:1, b:2, c:3, d:4 };)   -  person Manolo Santos    schedule 25.08.2016
comment
Я не нахожу это запутанным. Он действует именно так, как я и ожидал: const tmp = { a:1, b:2, c:3, d:4 }; const { c, d } = tmp; const { a, b } = tmp;   -  person Paul    schedule 25.08.2016
comment
@Paulpro Вы совершенно правы. Было несколько предложений сделать это с помощью деструктуризации, которые страдали именно от этой проблемы.   -  person    schedule 25.08.2016


Ответы (2)


Для этого я использую 2 вспомогательные функции

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;
};

Вы также можете сделать

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

const { a, b, c } = original;
const filtered = { a, b, c };
person Dmitriy Nevzorov    schedule 25.08.2016
comment
Да, сейчас я использую что-то вроде pickProps, но я хотел знать, есть ли прямая поддержка синтаксиса для этого случая. - person Manolo Santos; 25.08.2016

Я не думаю, что ваш способ «черного списка» хорош, потому что он без необходимости назначает original.evil на evil, а original.ugly на ugly.

Вы можете попробовать этот подход:

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() возвращает массив ключей объекта и соответствующие значения в формате [key, value], filter() фильтрует ключи в зависимости от того, включены ли они в черный или белый список, и reduce() преобразует массив [key, value] обратно в объект (аналогичный метод, как в этом ответ).

person Michał Perłakowski    schedule 25.08.2016
comment
Вы читали комментарии к этому вопросу? - person nils; 25.08.2016