Как получить подмножество свойств объекта javascript

Скажем, у меня есть объект:

elmo = { 
  color: 'red',
  annoying: true,
  height: 'unknown',
  meta: { one: '1', two: '2'}
};

Я хочу создать новый объект с подмножеством его свойств.

 // pseudo code
 subset = elmo.slice('color', 'height')

 //=> { color: 'red', height: 'unknown' }

Как я могу это достичь?

Ответ 1

Использование уничтожения объектов и сокращения свойств

const object = { a: 5, b: 6, c: 7  };
const picked = (({ a, c }) => ({ a, c }))(object);

console.log(picked); // { a: 5, c: 7 }

Ответ 2

Предлагаю взглянуть на Lodash; он имеет множество полезных функций.

Например pick() будет именно то, что вы ищете:

var subset = _.pick(elmo, ['color', 'height']);

fiddle

Ответ 3

Если вы используете ES6, есть очень лаконичный способ сделать это, используя деструктуру. Разрушение позволяет легко добавлять объекты к объекту с использованием разворота, но также позволяет создавать подмножества объектов таким же образом.

const object = {
  a: 'a',
  b: 'b',
  c: 'c',
  d: 'd',
}

// Remove "c" and "d" fields from original object:
const {c, d, ...partialObject} = object;
const subset = {c, d};

console.log(partialObject) // => { a: 'a', b: 'b'}
console.log(subset) // => { c: 'c', d: 'd'};

Ответ 4

Хотя это немного более многословно, вы можете выполнить то, что все остальные рекомендовали подчеркивание /lodash 2 года назад, используя Array.prototype.reduce.

var subset = ['color', 'height'].reduce(function(o, k) { o[k] = elmo[k]; return o; }, {});

Этот подход решает его с другой стороны: вместо того, чтобы брать объект и передавать ему имена свойств для извлечения, брать массив имен свойств и преобразовывать их в новый объект.

Хотя в простейшем случае это более многословно, обратный вызов здесь довольно удобен, поскольку вы можете легко выполнить некоторые общие требования, например, изменить свойство "color" на "color" для нового объекта, сгладить массивы и т.д. - любой из то, что вам нужно сделать при получении объекта из одной службы/библиотеки и создании нового объекта, необходимого где-то еще. Хотя подчеркивание /lodash - отличные, хорошо реализованные библиотеки, я предпочитаю подход, основанный на меньшей зависимости от поставщиков, и более простой и последовательный подход, когда логика построения подмножеств становится более сложной.

редактировать: версия es7 такая же:

const subset = ['color', 'height'].reduce((a, e) => (a[e] = elmo[e], a), {});

редактировать: хороший пример для карри тоже! Сделайте так, чтобы функция 'pick' возвращала другую функцию.

const pick = (...props) => o => props.reduce((a, e) => ({ ...a, [e]: o[e] }), {});

Вышеприведенный пример довольно близок к другому методу, за исключением того, что он позволяет создавать "сборщик" на лету. например

pick('color', 'height')(elmo);

Что особенно приятно в этом подходе, так это то, что вы можете легко передавать выбранные "пики" во все, что принимает функцию, например, Array#map:

[elmo, grover, bigBird].map(pick('color', 'height'));
// [
//   { color: 'red', height: 'short' },
//   { color: 'blue', height: 'medium' },
//   { color: 'yellow', height: 'tall' },
// ]

Ответ 5

Нет ничего подобного встроенной в базовую библиотеку, но вы можете использовать деструктуризацию объектов, чтобы сделать это...

const {color, height} = sourceObject;
const newObject = {color, height};

Вы также можете написать служебную функцию сделать это...

const cloneAndPluck = function(sourceObject, keys) {
    const newObject = {};
    keys.forEach((obj, key) => { newObject[key] = sourceObject[key]; });
    return newObject;
};

const subset = cloneAndPluck(elmo, ["color", "height"]);

Такие библиотеки, как Lodash, также имеют _.pick().

Ответ 6

Я добавляю этот ответ, потому что ни один из ответов не использовал Comma operator.

Это очень легко с destructuring assignment и , оператора

const object = { a: 5, b: 6, c: 7  };
const picked = ({a,c} = object, {a,c})

console.log(picked);

Ответ 7

Вы также можете использовать Lodash.

var subset = _.pick(elmo ,'color', 'height');

Дополняя, скажем, у вас есть массив "elmo" s:

elmos = [{ 
      color: 'red',
      annoying: true,
      height: 'unknown',
      meta: { one: '1', two: '2'}
    },{ 
      color: 'blue',
      annoying: true,
      height: 'known',
      meta: { one: '1', two: '2'}
    },{ 
      color: 'yellow',
      annoying: false,
      height: 'unknown',
      meta: { one: '1', two: '2'}
    }
];

Если вам нужно такое же поведение, используя lodash, вы просто:

var subsets = _.map(elmos, function(elm) { return _.pick(elm, 'color', 'height'); });

Ответ 8

Еще одно решение:

var subset = {
   color: elmo.color,
   height: elmo.height 
}

Это выглядит намного более читабельным для меня, чем практически любой ответ, но, возможно, это только я!

Ответ 9

Разбиение на динамически именованные переменные невозможно в JavaScript, как обсуждалось в этом вопросе.

Чтобы динамически устанавливать ключи, вы можете использовать функцию Reduce без изменения объекта следующим образом:

const getSubset = (obj, ...keys) => keys.reduce((a, c) => ({ ...a, [c]: obj[c] }), {});

const elmo = { 
  color: 'red',
  annoying: true,
  height: 'unknown',
  meta: { one: '1', two: '2'}
}

const subset = getSubset(elmo, 'color', 'annoying')
console.log(subset)

Ответ 10

Используйте метод pick из библиотеки lodash, если вы уже используете.

var obj = { 'a': 1, 'b': '2', 'c': 3 };

_.pick(object, ['a', 'c']);

// => { 'a': 1, 'c': 3 }

https://lodash.com/docs/4.17.10#pick

Ответ 11

Еще один способ...

var elmo = { 
  color: 'red',
  annoying: true,
  height: 'unknown',
  meta: { one: '1', two: '2'}
}

var subset = [elmo].map(x => ({
  color: x.color,
  height: x.height
}))[0]

Вы можете использовать эту функцию с массивом объектов =)

Ответ 12

Это работает для меня в консоли Chrome. Любая проблема с этим?

var { color, height } = elmo
var subelmo = { color, height }
console.log(subelmo) // {color: "red", height: "unknown"}

Ответ 13

Однострочник для произвольного списка выбранных ключей становится короче с каждым выпуском JS:

ES5

Object.keys(obj)
.filter(function (key) { 
  return ['foo', 'bar'].indexOf(key) >= 0;
})
.reduce(function (obj2, key) {
  obj2[key] = obj[key];
  return obj2;
}, {});

ES6

Object.keys(obj)
.filter(key => ['foo', 'bar'].indexOf(key) >= 0)
.reduce((obj2, key) => Object.assign(obj2, { [key]: obj[key] }), {});

Или с запятой оператор:

Object.keys(obj)
.filter(key => ['foo', 'bar'].indexOf(key) >= 0)
.reduce((obj2, key) => (obj2[key] = obj[key], obj2), {});

ES2019

ECMAScript 2017 имеет Object.entries и Array.prototype.includes, ECMAScript 2019 имеет Object.fromEntries, они могут быть заполнены при необходимости и упростить задачу:

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

Ответ 14

Как насчет:

function sliceObj(obj) {
  var o = {}
    , keys = [].slice.call(arguments, 1);
  for (var i=0; i<keys.length; i++) {
    if (keys[i] in obj) o[keys[i]] = obj[keys[i]];
  }
  return o;
}

var subset = sliceObj(elmo, 'color', 'height');

Ответ 15

  1. преобразовать аргументы в массив

  2. используйте Array.forEach() чтобы выбрать свойство

    Object.prototype.pick = function(...args) {
       var obj = {};
       args.forEach(k => obj[k] = this[k])
       return obj
    }
    var a = {0:"a",1:"b",2:"c"}
    var b = a.pick('1','2')  //output will be {1: "b", 2: "c"}
    

Ответ 16

Назначение деструктурирования с динамическими свойствами

Это решение применяется не только к вашему конкретному примеру, но и в более общем смысле:

const subset2 = (x, y) => ({[x]:a, [y]:b}) => ({[x]:a, [y]:b});

const subset3 = (x, y, z) => ({[x]:a, [y]:b, [z]:c}) => ({[x]:a, [y]:b, [z]:c});

// const subset4...etc.


const o = {a:1, b:2, c:3, d:4, e:5};


const pickBD = subset2("b", "d");
const pickACE = subset3("a", "c", "e");


console.log(
  pickBD(o), // {b:2, d:4}
  pickACE(o) // {a:1, c:3, e:5}
);

Ответ 17

Динамическое решение

['color', 'height'].reduce((a,b) => (a[b]=elmo[b],a), {})

let elmo = { 
  color: 'red',
  annoying: true,
  height: 'unknown',
  meta: { one: '1', two: '2'}
};

let subset= ['color', 'height'].reduce((a,b)=> (a[b]=elmo[b],a),{});

console.log( subset );

Ответ 18

Решение TypeScript:

export function pick<T extends object, U extends keyof T>(obj: T, paths: Array<U>) {
    return paths.reduce((o, k) => {
        o[k] = obj[k];
        return o;
    }, Object.create(null));
}

Информация о наборе даже допускает автозаполнение:

Кредит на DefiniteTyped для U extends keyof T !

Ответ 19

Вот полное решение для Node.js

>>> npm i --save lodash.pick
var pick = require('lodash.pick');

var user = {name: 'Bill', number:'1', age:'10'}
var subset =  pick(user, ['name', 'number']);

Ответ 20

elmo.slice был бы "плохим", потому что его нужно было бы положить в Object.prototype, но вы могли бы сделать что-то вроде этого:

Object.slice = function(obj, props) {
    var ret = {};
    for(var i = 0, l = props.length; i < l; i++) {
        var prop = props[i];
        if(obj.hasOwnProperty(prop)) {
            ret[prop] = obj[prop];
        }
    }
    return ret;
}

Ответ 21

function splice()
{
    var ret = new Object();

    for(i = 1; i < arguments.length; i++)
        ret[arguments[i]] = arguments[0][arguments[i]];

    return ret;
}

var answer = splice(elmo, "color", "height");

Ответ 22

Старый Array.prototype.reduce:

const selectable = {a: null, b: null};
const v = {a: true, b: 'yes', c: 4};

const r = Object.keys(selectable).reduce((a, b) => {
  return (a[b] = v[b]), a;
}, {});

console.log(r);

этот ответ использует магический оператор запятой, а также: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator

если вы хотите стать действительно модным, это более компактно:

const r = Object.keys(selectable).reduce((a, b) => (a[b] = v[b], a), {});

Собираем все вместе в многократно используемую функцию:

const getSelectable = function (selectable, original) {
  return Object.keys(selectable).reduce((a, b) => (a[b] = original[b], a), {})
};

const r = getSelectable(selectable, v);
console.log(r);

Ответ 23

Пытаться

const elmo={color:"red",annoying:!0,height:"unknown",meta:{one:"1",two:"2"}};

const {color, height} = elmo; newObject = ({color, height});

console.log(newObject); //{ color: 'red', height: 'unknown' }

Ответ 24

Примечание: хотя исходный вопрос был задан для javascript, это может быть сделанный jQuery ниже решения

вы можете расширить jquery, если хотите, вот пример кода для одного фрагмента:

jQuery.extend({
  sliceMe: function(obj, str) {
      var returnJsonObj = null;
    $.each( obj, function(name, value){
        alert("name: "+name+", value: "+value);
        if(name==str){
            returnJsonObj = JSON.stringify("{"+name+":"+value+"}");
        }

    });
      return returnJsonObj;
  }
});

var elmo = { 
  color: 'red',
  annoying: true,
  height: 'unknown',
  meta: { one: '1', two: '2'}
};


var temp = $.sliceMe(elmo,"color");
alert(JSON.stringify(temp));

вот скрипка для того же: http://jsfiddle.net/w633z/