Недавно у нас появилось требование в нашем NodeJS API — возвращать массив объектов, каждый из которых был подмножеством исходного объекта.
Если это звучит загадочно, пример поможет проиллюстрировать.
Наши исходные данные были примерно такими.
[ { "id": 1, "name": "testData1", "value": "CONSTANT", "config": "rootEVAL", "status": "Active", "Desc": "This is description of test data 1" },{ "id": 2, "name": "testData2", "value": "MULTIPLY", "config": "rootEVAL", "status": "InActive", "Desc": "This is a description of test data 2" }, ... ]
У нас было два API — один для получения list
данных, а другой для заданного id
возвращал конкретный object
.
Для list
мы не хотели возвращать все поля каждого объекта, а только подмножество. В этом случае,
[{ "id": 1, "name": "testData1", "status": "Active", }, { "id": 2, "name": "testData2", "status": "InActive", }, ... ]
Теперь, как нам получить подмножество объектов — точнее, массив подмножеств данных?
Javascript такой, какой он есть, он предоставляет ряд различных опций.
Быстрый поиск в stackoverflow дает нам среди прочего эту ссылку. Мы можем использовать старый добрый цикл for
, метод reduce
с служебными методами filter
, lodash
и так далее.
В нашем случае нам также необходимо иметь массив таких объектов.
Решение, которое мы в итоге использовали, оказалось довольно простым, но элегантным.
// res being nodejs response object res.json(data.map(({id, name, status}) => ({id, name, status})))
data
является исходным массивом
На первый взгляд выглядит забавно, особенно одинаковые поля с обеих сторон с несколькими скобками в придачу. Эта средняя статья отчасти проливает свет на синтаксис.
Мы хотим
data.map(item => { return { id: item.id, name: item.name, status: item.status } }
По сути, для каждого item
в массиве data
возвращайте объект, который имеет поля id
, name
и status
.
Теперь мы также знаем, что нам не нужно использовать return
для однострочной функции. Например
const add = (a, b) => a + b console.log(add(2,3)) // Output: 5
Это нормально для примитивных типов данных. Но как это работает для объектов?
const employee = (name, age) => { name, age } console.log(employee("Jack Sparrow", 35)) // Output: undefined
Да, это работает, если мы предоставим return
const employee = (name, age) => {return { name, age };} console.log(employee("Jack Sparrow", 35)) // Output: {name: 'Jack Sparrow', age: 35}
Но мы хотим избежать оператора return
.
Здесь нам на помощь приходит скобка ()
.
Так вот этот работает
const employee = (name, age) => ({ name, age }) console.log(employee("Jack Sparrow", 35)) // Output: {name: 'Jack Sparrow', age: 35}
Итак, это объясняет правую часть нашего кода.
data.map(({id, name, status}) => ({id, name, status}))
Если вы посмотрите на нашу правую часть, мы делаем сокращенные имена свойств, а не
{id: id, name: name, status: status}
Если мы повторим каждый элемент data
, используя объект, скажем, item
, то мы запишем это как
data.map(item => ({id: item.id, name: item.name, status; item.status})
Вот где проявляется object dereferencing
особенность javascript. Мы можем извлечь из объекта только релевантные поля с помощью
{ id, name, status} = item
Как только мы это сделаем, имя поля и имя переменной станут одинаковыми. Поэтому можно использовать сокращенное имя свойства.
data.map(({id, name, status}) => ({id, name, status}))
Виола! Теперь мы можем получить массив, содержащий подмножество полей нашего исходного объекта!