Один лайнер для отримання деяких властивостей з об'єкта в ES 6


153

Як можна записати функцію, яка займає лише кілька атрибутів найбільш компактно в ES6?

Я придумав рішення, використовуючи деструктуризацію + спрощений буквальний об'єкт, але мені не подобається, що список полів повторюється в коді.

Чи є ще стрункіше рішення?

(v) => {
    let { id, title } = v;
    return { id, title };
}

Відповіді:


124

Ось щось стрункіше, хоча це не уникне повторення списку полів. Він використовує "деструктурування параметрів", щоб уникнути необхідності цього vпараметра.

({id, title}) => ({id, title})

(Дивіться приклад, який можна виконати в цій іншій відповіді ).

@ Рішення EthanBrown є більш загальним. Ось більш ідіоматична його версія, яка використовує Object.assignта обчислювані властивості ( [p]частина):

function pick(o, ...props) {
    return Object.assign({}, ...props.map(prop => ({[prop]: o[prop]})));
}

Якщо ми хочемо зберегти атрибути властивостей, наприклад, configurablegetters і setters, опустивши також неперелічені властивості, то:

function pick(o, ...props) {
    var has = p => o.propertyIsEnumerable(p),
        get = p => Object.getOwnPropertyDescriptor(o, p);

    return Object.defineProperties({},
        Object.assign({}, ...props
            .filter(prop => has(prop))
            .map(prop => ({prop: get(props)})))
    );
}

10
+1 приємна відповідь, торазабуро; спасибі за те, що мене зрозуміли Object.assign; es6 - це як ялинка з такою кількістю подарунків під нею Я все ще знаходжу подарунки через місяці після свята
Етан Браун

Помилка: Опис властивості повинен бути об'єктом: не визначено. Чи не повинно бути filter(...).map(prop => ({[prop]: get(prop)})))?
Нескінченний

Для своєї першої pick()реалізації ви також можете зробити щось на кшталтreturn props.reduce((r, prop) => (r[prop] = o[prop], r), {})
Патрік Робертс,

на жаль, версія вибору не буде безпечною для потоку чи typecript. якщо ви хочете ввести безпеку, не можна обійтися присвоєнням деструкції оригінального об'єкта, а потім присвоєння кожному новому об'єкту.
duhseekoh

Коли властивість не існує в об'єкті, ви отримуєте undefined. Іноді це має значення. Крім того, приємна ідея.
x-yuri

43

Я не думаю, що існує якийсь спосіб зробити його набагато більш компактним, ніж ваша відповідь (або торазбуро), але по суті те, що ви намагаєтесь зробити, це імітувати операцію Underscorepick . Було б досить легко реалізувати це в ES6:

function pick(o, ...fields) {
    return fields.reduce((a, x) => {
        if(o.hasOwnProperty(x)) a[x] = o[x];
        return a;
    }, {});
}

Тоді у вас є зручна функція повторного використання:

var stuff = { name: 'Thing', color: 'blue', age: 17 };
var picked = pick(stuff, 'name', 'age');

Дякую. Це не відповідь на моє запитання, але дуже приємне доповнення.
киріллоїд

7
(Знизавши плечима) Я відчуваю , що це є відповіддю на ваше рішення; не існує більш тонкого загального рішення (рішення torazaburo видаляє зайвий верф, але головна проблема - те, що всі імена властивостей повинні бути записані двічі - означає, що це не масштабніше, ніж ваше рішення). Моє рішення принаймні добре масштабує ... виправте pickфункцію один раз, і ви можете вибрати скільки завгодно властивостей, і це не подвоїть їх.
Етан Браун

1
Для чого ви використовуєте hasOwnProperty? Якщо поля обрані вручну, навіть inздається, що це більш доречно; хоча я б хотів пропустити чек повністю і просто дозволити їм за замовчуванням undefined.
Бергі

Бергі, це розумний момент ... Я просто вважаю властивості (а не методи) ланцюга прототипу дивними та "смердючими" (як у них запах коду), і я вважаю за краще за замовчуванням відфільтрувати їх. Якщо є програма, яка потребує властивостей прототипу, ну ... може бути варіант для цього.
Етан Браун

що з масивами json!
Rizwan Patel

19

Трюк для вирішення цього питання як однолінійного - перевернути підхід: замість того, щоб починати з оригінального об'єкта orig, можна починати з ключів, які вони хочуть витягти.

Використовуючи Array#reduceодин може потім зберегти кожен необхідний ключ на порожній об'єкт , який передається в якості initialValueдля зазначеної функції.

Так:

const orig = {
  id: 123456789,
  name: 'test',
  description: '…',
  url: 'https://…',
};

const filtered = ['id', 'name'].reduce((result, key) => { result[key] = orig[key]; return result; }, {});

console.log(filtered); // Object {id: 123456789, name: "test"}


11

Трохи коротше рішення за допомогою оператора кома:

const pick = (O, ...K) => K.reduce((o, k) => (o[k]=O[k], o), {})

console.log(
  pick({ name: 'John', age: 29, height: 198 }, 'name', 'age')
)  


як це використовувати? Чи можете ви навести приклад?
Томаш М

1
Він працює так само, як і інші pickфункції в цій темі:pick({ name: 'John', age: 29, height: 198 }, 'name', 'age')
shesek

8

Пропозиція щодо властивостей об'єкта TC39 щодо решти / розповсюдження зробить це дуже просто:

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
z; // { a: 3, b: 4 }

(У нього є недолік створення xта yзмінних, які вам можуть не знадобитися.)


33
Це зручна форма omit, але неpick
кіріллоїд

5
Я хотів би побачити варіант, який робить протилежне до цього, як пропозиція ES:let { a, b } as z = { x: 1, y: 2, a: 3, b: 4 }
gfullam

3

Ви можете використовувати деструктуризацію об'єктів для розпакування властивостей із існуючого об'єкта та присвоєння їм змінних з різними іменами - полями нового, спочатку порожнього об'єкта.

const person = {
  fname: 'tom',
  lname: 'jerry',
  aage: 100,
}

let newPerson = {};

({fname: newPerson.fname, lname: newPerson.lname} = person);

console.log(newPerson);


(індекс): 36 Uncaught SyntaxError: Недійсна ціль деструктування
Remzes

@Remzes не знаю, де і як ви це виконуєте, але це добре працює в редакторі кодів SO та в хромованих інструментах для розробників.
Сакшам

Я використав jsfiddle
Remzes

Я трохи покращив вашу відповідь, але це все ще занадто багатослівно, порівняно з тим, що вимагала ОП. Він повторює не тільки назви полів, але й назву нового об’єкта.
Дан Даскалеску

3

ES6 була останньою специфікацією в той час, коли питання було написане. Як пояснено у цій відповіді , вибір клавіш у ES2019 значно коротший, ніж у ES6:

Object.fromEntries(
  Object.entries(obj)
  .filter(([key]) => ['foo', 'bar'].includes(key))
)

2

Наразі є пропозиція щодо вдосконалення синтаксису стенограми об'єкта JavaScript, що дозволило б "вибрати" названі властивості без повторення:

const source = {id: "68646", genre: "crime", title: "Scarface"};
const target = {};
Object.assign(target, {source.title, source.id});

console.log(picked);
// {id: "68646", title: "Scarface"}

На жаль, здається, що ця пропозиція незабаром нікуди не дінеться. Останнє редагування в липні 2017 року і все ще залишається чернетом на етапі 0 , припускаючи, що автор, можливо, вийшов з нього або забув про нього.

ES5 та новіші версії (нестрогий режим)

Найкоротший можливий стенограф, який я можу припустити, включає стародавню мову, яку ніхто більше не використовує:

Object.assign(target, {...(o => {
    with(o) return { id, title };
})(source)});

withзаяви заборонені в суворому режимі, що робить цей підхід марним для 99,999% сучасного JavaScript. Соромно, бо це єдине наполовину гідне використання, яке я знайшов для цієї withфункції. 😀


1

У мене схоже рішення Етана Брауна, але ще коротше - pickфункція. Інша функція pick2трохи довша (і повільніше), але дозволяє перейменовувати властивості аналогічно ES6.

const pick = (o, ...props) => props.reduce((r, p) => p in o ? {...r, [p]: o[p]} : r, {})

const pick2 = (o, ...props) => props.reduce((r, expr) => {
  const [p, np] = expr.split(":").map( e => e.trim() )
  return p in o ? {...r, [np || p]: o[p]} : r
}, {}) 

Ось приклад використання:

const d = { a: "1", c: "2" }

console.log(pick(d, "a", "b", "c"))        // -> { a: "1", c: "2" }
console.log(pick2(d, "a: x", "b: y", "c")) // -> { x: "1", c: "2" }

1
Що є причиною недопущення? Це не працює для вас?
Олександр Приєжев

0

Я вимагав цього розпусту, але я не знав, чи пропонуються запропоновані ключі. Отже, я взяв @torazaburo відповідь та покращив для свого випадку використання:

function pick(o, ...props) {
  return Object.assign({}, ...props.map(prop => {
    if (o[prop]) return {[prop]: o[prop]};
  }));
}

// Example:
var person = { name: 'John', age: 29 };
var myObj = pick(person, 'name', 'sex'); // { name: 'John' }

0

натхненний скороченням https://stackoverflow.com/users/865693/shesek :

const pick = (orig, ...keys) => keys.reduce((acc, key) => ({...acc, [key]: orig[key]}), {})

використання:

pick({ model : 'F40', manufacturer: 'Ferrari', productionYear: 1987 }, 'model', 'productionYear') призводить до: {model: "F40", productionYear: 1987}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.