如何获取javascript对象属性的子集

时间:2013-07-22 06:47:21

标签: javascript

说我有一个对象:

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

我想用一个属性的子集创建一个新对象。

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

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

我怎么能实现这个目标?

31 个答案:

答案 0 :(得分:451)

使用对象解构和属性简写



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

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




来自Philipp Kewisch:

  

这实际上只是一个即时调用的匿名函数。所有这些都可以在MDN的Destructuring Assignment页面上找到。这是一个扩展的表格



let unwrap = ({a, c}) => ({a, c});

let unwrap2 = function({a, c}) { return { a, c }; };

let picked = unwrap({ a: 5, b: 6, c: 7 });

let picked2 = unwrap2({a: 5, b: 6, c: 7})

console.log(picked)
console.log(picked2)




答案 1 :(得分:104)

我建议看看Lodash;它有很多很棒的实用功能。

例如,pick()正是您所寻求的:

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

fiddle

答案 2 :(得分:71)

如果您正在使用ES6,则可以使用destruct以非常简洁的方式执行此操作。 Destructing允许您使用spread轻松地添加对象,但它也允许您以相同的方式创建子集对象。

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

答案 3 :(得分:55)

虽然它有点冗长,但是通过使用Array.prototype.reduce,你可以完成2年前其他人推荐使用下划线/ lodash的内容。

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] }), {});

以上与其他方法非常接近,只是它可以让你动态构建一个“选择器”。 e.g。

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' },
// ]

答案 4 :(得分:25)

核心库中没有内置的东西,但你可以使用对象解构来实现它......

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()

答案 5 :(得分:11)

我想在这里提到that很好的策展:

pick-es2019.js

Object.fromEntries(
  Object.entries(obj)
  .filter(([key]) => ['whitelisted', 'keys'].includes(key))
);

pick-es2017.js

Object.entries(obj)
.filter(([key]) => ['whitelisted', 'keys'].includes(key))
.reduce((obj, [key, val]) => Object.assign(obj, { [key]: val }), {});

pick-es2015.js

Object.keys(obj)
.filter((key) => ['whitelisted', 'keys'].indexOf(key) >= 0)
.reduce((newObj, key) => Object.assign(newObj, { [key]: obj[key] }), {})

omit-es2019.js

Object.fromEntries(
  Object.entries(obj)
  .filter(([key]) => !['blacklisted', 'keys'].includes(key))
);

omit-es2017.js

Object.entries(obj)
.filter(([key]) => !['blacklisted', 'keys'].includes(key))
.reduce((obj, [key, val]) => Object.assign(obj, { [key]: val }), {});

omit-es2015.js

Object.keys(obj)
.filter((key) => ['blacklisted', 'keys'].indexOf(key) < 0)
.reduce((newObj, key) => Object.assign(newObj, { [key]: obj[key] }), {})

答案 6 :(得分:10)

我添加此答案是因为没有答案使用Comma operator

使用destructuring assignment,运算符非常简单

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

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

答案 7 :(得分:9)

您也可以使用Lodash

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

补充一下,假设你有一系列“elmo”:

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 :(得分:9)

还有一个解决方案:

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

到目前为止,这看起来比任何答案都要可读得多,但也许只是我!

答案 9 :(得分:8)

如JavaScript question中所述,在JavaScript中无法对动态命名变量进行解构。

动态设置密钥,您可以使用reduce功能而不会变更对象,如下所示:

&#13;
&#13;
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)
&#13;
&#13;
&#13;

  

应注意,您在每次迭代时都创建了一个新对象,而不是更新单个克隆。 - mpen

下面是使用reduce with single clone的版本(更新传入的初始值为reduce)。

&#13;
&#13;
const getSubset = (obj, ...keys) => keys.reduce((acc, curr) => {
  acc[curr] = obj[curr]
  return acc
}, {})

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

const subset = getSubset(elmo, 'annoying', 'height', 'meta')
console.log(subset)
&#13;
&#13;
&#13;

答案 10 :(得分:4)

另一种方式......

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]

您可以将此函数与Objects =)

数组一起使用

答案 11 :(得分:4)

如果已经使用lodash库,请使用pick方法。

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

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

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

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

答案 12 :(得分:2)

使用带有缩写对象文字语法的“ with”语句

到目前为止,还没有人演示这种方法,可能是因为它很糟糕,您不应该这样做,但是我觉得必须列出它。

var o = {a:1,b:2,c:3,d:4,e:4,f:5}
with(o){
  var output =  {a,b,f}
}
console.log(output)

专业人士:您不必两次输入属性名称。

缺点:由于许多原因,不建议使用“ with”语句。

结论:它很好用,但不要使用。

答案 13 :(得分:2)

在每个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.entriesArray.prototype.includes,ECMAScript 2019具有Object.fromEntries,可以在需要时对其进行填充,从而使任务更容易:

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

答案 14 :(得分:2)

这适用于Chrome控制台。这有什么问题吗?

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

答案 15 :(得分:2)

要添加另一种深奥的方法,这也可以:

var obj = {a: 1, b:2, c:3}
var newobj = {a,c}=obj && {a,c}
// {a: 1, c:3}

但是您必须写两次道具名称。

答案 16 :(得分:1)

这是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']);

答案 17 :(得分:1)

我遇到了同样的问题,可以使用以下库轻松解决它:

object.pick

https://www.npmjs.com/package/object.pick

pick({a: 'a', b: 'b', c: 'c'}, ['a', 'b'])
//=> {a: 'a', b: 'b'}

object.omit

https://www.npmjs.com/package/object.omit

omit({a: 'a', b: 'b', c: 'c'}, ['a', 'c'])
//=> { b: 'b' }

答案 18 :(得分:1)

动态解决方案

['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 );

答案 19 :(得分:1)

使用动态属性进行解构分配

此解决方案不仅适用于您的具体示例,而且更为普遍适用:

&#13;
&#13;
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}
);
&#13;
&#13;
&#13;

您可以轻松定义subset4等,以考虑更多属性。

答案 20 :(得分:1)

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

答案 21 :(得分:1)

我发现的最简单的方法(不会创建不必要的变量)是一个可以调用的函数,并且与 lodash 的工作方式相同,如下所示:

pick(obj, keys){
    return  Object.assign({}, ...keys.map(key => ({ [key]: obj[key] })))
}

例如:

pick(obj, keys){
    return  Object.assign({}, ...keys.map(key => ({ [key]: obj[key] })))
}
const obj = {a:1, b:2, c:3, d:4}
const keys = ['a', 'c', 'f']
const picked = pick(obj,keys)
console.log(picked)

pick = (obj, keys) => {
  return Object.assign({}, ...keys.map(key => ({
    [key]: obj[key]
  })))
}

const obj = {
  a: 1,
  b: 2,
  c: 3,
  d: 4
}
const keys = ['a', 'c', 'f']

const picked = pick(obj, keys)
console.log(picked)

答案 22 :(得分:1)

怎么样:

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');

答案 23 :(得分:0)

对象数组

aListOfObjects = [
  {
      prop1: 50,
      prop2: "Nothing",
      prop3: "hello",
      prop4: "What's up",
},
 {
      prop1: 88,
      prop2: "Whatever",
      prop3: "world",
      prop4: "You get it",
},
]

通过这种方式破坏对象可以实现一个或多个对象的子集。

  const sections = aListOfObjects.map(({prop1, prop2}) => ({prop1, prop2})

答案 24 :(得分:0)

像这个线程上的几个一样,我同意最明显的老派方法实际上是最好的,但是为了好玩,让我在某些情况下提供另一种不明智的方法,比如当你已经有了您的子集已定义,并且您希望从另一个包含超集或相交属性集的对象向其复制属性。

let set = { a : 1, b : 2, c : 3 };
let subset = { a : null, b : null };
try {
  Object.assign(Object.seal(subset), set);
} catch (e) {
  console.log('its ok I meant to do that <(^.^)^');
}
console.log(subset);

答案 25 :(得分:0)

将我的2美分加到Ivan Nosov答案中:

在我的情况下,我需要从对象中“切出”许多键,因此它变得非常丑陋,而且不是一种动态解决方案:

fibonacci.js

这是使用eval的动态解决方案:

const object = { a: 5, b: 6, c: 7, d: 8, aa: 5, bb: 6, cc: 7, dd: 8, aaa: 5, bbb: 6, ccc: 7, ddd: 8, ab: 5, bc: 6, cd: 7, de: 8  };
const picked = (({ a, aa, aaa, ab, c, cc, ccc, cd }) => ({ a, aa, aaa, ab, c, cc, ccc, cd }))(object);

console.log(picked);

答案 26 :(得分:0)

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

键入信息甚至可以自动完成:

U extends keyof T技巧获得DefinitelyTyped的奖励!

答案 27 :(得分:0)

尝试

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

答案 28 :(得分:0)

古老的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);

答案 29 :(得分:0)

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");

答案 30 :(得分:-2)

  

注意:虽然问的原始问题是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/