javascript 如何获取javascript对象属性的子集
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17781472/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get a subset of a javascript object's properties
提问by Christian Schlensker
Say I have an object:
说我有一个对象:
elmo = {
color: 'red',
annoying: true,
height: 'unknown',
meta: { one: '1', two: '2'}
};
I want to make a new object with a subset of its properties.
我想使用其属性的子集创建一个新对象。
// pseudo code
subset = elmo.slice('color', 'height')
//=> { color: 'red', height: 'unknown' }
How may I achieve this?
我怎样才能做到这一点?
回答by Ivan Nosov
Using Object Destructuring and Property Shorthand
使用对象解构和属性速记
const object = { a: 5, b: 6, c: 7 };
const picked = (({ a, c }) => ({ a, c }))(object);
console.log(picked); // { a: 5, c: 7 }
From Philipp Kewisch:
菲利普·凯维希 (Philipp Kewisch):
This is really just an anonymous function being called instantly. All of this can be found on the Destructuring Assignmentpage on MDN. Here is an expanded form
这实际上只是一个被立即调用的匿名函数。所有这些都可以在 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)
回答by Ygg
回答by Lauren
If you are using ES6 there is a very concise way to do this using destructuring. Destructuring allows you to easily add on to objects using a spread, but it also allows you to make subset objects in the same way.
如果您使用的是 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'};
回答by Josh from Qaribou
While it's a bit more verbose, you can accomplish what everyone else was recommending underscore/lodash for 2 years ago, by using Array.prototype.reduce.
虽然它有点冗长,但您可以通过使用Array.prototype.reduce来完成其他人在 2 年前推荐下划线/lodash 的内容。
var subset = ['color', 'height'].reduce(function(o, k) { o[k] = elmo[k]; return o; }, {});
This approach solves it from the other side: rather than take an object and pass property names to it to extract, take an array of property names and reduce them into a new object.
这种方法从另一方面解决了它:不是获取一个对象并将属性名称传递给它来提取,而是获取一个属性名称数组并将它们缩减为一个新对象。
While it's more verbose in the simplest case, a callback here is pretty handy, since you can easily meet some common requirements, e.g. change the 'color' property to 'colour' on the new object, flatten arrays, etc. -- any of the things you need to do when receiving an object from one service/library and building a new object needed somewhere else. While underscore/lodash are excellent, well-implemented libs, this is my preferred approach for less vendor-reliance, and a simpler, more consistent approach when my subset-building logic gets more complex.
虽然在最简单的情况下更冗长,但这里的回调非常方便,因为您可以轻松满足一些常见要求,例如将新对象上的“颜色”属性更改为“颜色”、展平数组等——任何一个从一个服务/库接收对象并构建其他地方需要的新对象时需要做的事情。虽然 underscore/lodash 是优秀的、实现良好的库,但这是我首选的方法,以减少对供应商的依赖,当我的子集构建逻辑变得更复杂时,这是一种更简单、更一致的方法。
edit: es7 version of the same:
编辑:es7 版本相同:
const subset = ['color', 'height'].reduce((a, e) => (a[e] = elmo[e], a), {});
edit: A nice example for currying, too! Have a 'pick' function return another function.
编辑:也是咖喱的一个很好的例子!让一个“pick”函数返回另一个函数。
const pick = (...props) => o => props.reduce((a, e) => ({ ...a, [e]: o[e] }), {});
The above is pretty close to the other method, except it lets you build a 'picker' on the fly. e.g.
上面的方法与另一种方法非常接近,只是它可以让您即时构建“选择器”。例如
pick('color', 'height')(elmo);
What's especially neat about this approach, is you can easily pass in the chosen 'picks' into anything that takes a function, e.g. Array#map
:
这种方法特别巧妙的是,您可以轻松地将所选的“选择”传递到任何带有函数的东西中,例如Array#map
:
[elmo, grover, bigBird].map(pick('color', 'height'));
// [
// { color: 'red', height: 'short' },
// { color: 'blue', height: 'medium' },
// { color: 'yellow', height: 'tall' },
// ]
回答by Estus Flask
ES6 destructuring
ES6解构
Destructuring syntaxallows to destructure and recombine an object, with either function parameters or variables.
解构语法允许使用函数参数或变量对对象进行解构和重组。
The limitation is that a list of keys is predefined, they cannot be listed as strings, as the question mentions. Destructuring becomes more complicated if a key is non-alphanumeric, e.g. foo_bar
.
限制是键列表是预定义的,它们不能作为字符串列出,如问题所述。如果键是非字母数字的,例如foo_bar
.
The downside is that this requires to duplicate a list of keys, this results in verbose code in case a list is long. Since destructuring duplicates object literal syntax in this case, a list can be copied and pasted as is.
缺点是这需要复制一个键列表,如果列表很长,这会导致冗长的代码。由于在这种情况下解构复制了对象文字语法,因此可以按原样复制和粘贴列表。
The upside is that it's performant solution that is natural to ES6.
好处是它是 ES6 自然的高性能解决方案。
IIFE
国际金融研究所
let subset = (({ foo, bar }) => ({ foo, bar }))(obj); // dupe ({ foo, bar })
Temporary variables
临时变量
let { foo, bar } = obj;
let subset = { foo, bar }; // dupe { foo, bar }
A list of strings
字符串列表
Arbitrary list of picked keys consists of strings, as the question requires. This allows to not predefine them and use variables that contain key names, like pick(obj, 'foo', someKey, ...moreKeys)
.
正如问题所要求的那样,任意选择的键列表由字符串组成。这允许不预定义它们并使用包含键名称的变量,例如pick(obj, 'foo', someKey, ...moreKeys)
.
A one-liner becomes shorter with each JS edition.
每个 JS 版本的单行都变得更短。
ES5
ES5
var subset = Object.keys(obj)
.filter(function (key) {
return ['foo', 'bar'].indexOf(key) >= 0;
})
.reduce(function (obj2, key) {
obj2[key] = obj[key];
return obj2;
}, {});
ES6
ES6
let subset = Object.keys(obj)
.filter(key => ['foo', 'bar'].indexOf(key) >= 0)
.reduce((obj2, key) => Object.assign(obj2, { [key]: obj[key] }), {});
Or with comma operator:
或使用逗号运算符:
let subset = Object.keys(obj)
.filter(key => ['foo', 'bar'].indexOf(key) >= 0)
.reduce((obj2, key) => (obj2[key] = obj[key], obj2), {});
ES2019
ES2019
ECMAScript 2017 has Object.entries
and Array.prototype.includes
, ECMAScript 2019 has Object.fromEntries
, they can be polyfilled when needed and make the task easier:
ECMAScript 2017 具有Object.entries
和Array.prototype.includes
,ECMAScript 2019 具有Object.fromEntries
,它们可以在需要时进行 polyfill,使任务更容易:
let subset = Object.fromEntries(
Object.entries(obj)
.filter(([key]) => ['foo', 'bar'].includes(key))
)
A one-liner can be rewritten as helper function similar to Lodash pick
or omit
where the list of keys is passed through arguments:
单行可以重写为类似于Lodash 的pick
辅助函数,或者omit
通过参数传递键列表:
let pick = (obj, ...keys) => Object.fromEntries(
Object.entries(obj)
.filter(([key]) => keys.includes(key))
);
let subset = pick({ foo: 1, qux: 2 }, 'foo', 'bar'); // { foo: 1 }
A note about missing keys
关于丢失钥匙的注意事项
The major difference between destructuring and conventional Lodash-like pick
function is that destructuring includes non-existent picked keys with undefined
value in a subset:
解构和传统的类似 Lodash 的pick
函数之间的主要区别在于,解构包括不存在的、undefined
在子集中具有值的选择键:
(({ foo, bar }) => ({ foo, bar }))({ foo: 1 }) // { foo: 1, bar: undefined }
This behaviour may or not be desirable. It cannot be changed for destructuring syntax.
这种行为可能是可取的,也可能是不可取的。它不能因解构语法而改变。
While pick
can be changed to include missing keys by iterating a list of picked keys instead:
虽然pick
可以通过迭代选择的键列表来更改为包含丢失的键:
let inclusivePick = (obj, ...keys) => Object.fromEntries(
keys.map(key => [key, obj[key]])
);
let subset = inclusivePick({ foo: 1, qux: 2 }, 'foo', 'bar'); // { foo: 1, bar: undefined }
回答by alex
There is nothing like that built-in to the core library, but you can use object destructuring to do it...
核心库中没有类似的东西,但是您可以使用对象解构来做到这一点......
const {color, height} = sourceObject;
const newObject = {color, height};
You could also write a utility function do it...
你也可以写一个实用函数来做...
const cloneAndPluck = function(sourceObject, keys) {
const newObject = {};
keys.forEach((obj, key) => { newObject[key] = sourceObject[key]; });
return newObject;
};
const subset = cloneAndPluck(elmo, ["color", "height"]);
Libraries such as Lodash also have _.pick()
.
Lodash 等图书馆也有_.pick()
.
回答by Code Maniac
I am adding this answer because none of the answer used Comma operator
.
我添加此答案是因为没有使用任何答案Comma operator
。
It's very easy with destructuring assignment
and ,
operator
destructuring assignment
和,
操作符很容易
const object = { a: 5, b: 6, c: 7 };
const picked = ({a,c} = object, {a,c})
console.log(picked);
With a certain enhancement for dynamic properties assignment it could look like this:
通过对动态属性分配的某种增强,它可能如下所示:
回答by Evert
One more solution:
另一种解决方案:
var subset = {
color: elmo.color,
height: elmo.height
}
This looks far more readable to me than pretty much any answer so far, but maybe that's just me!
对我来说,这看起来比迄今为止的任何答案都更具可读性,但也许这就是我!
回答by Arthur Alvim
You can use Lodashalso.
您也可以使用Lodash。
var subset = _.pick(elmo ,'color', 'height');
Complementing, let's say you have an array of "elmo"s :
作为补充,假设您有一组“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'}
}
];
If you want the same behavior, using lodash, you would just:
如果您想要相同的行为,使用 lodash,您只需:
var subsets = _.map(elmos, function(elm) { return _.pick(elm, 'color', 'height'); });
回答by Muhammet Enginar
Destructuring into dynamically named variables is impossible in JavaScript as discussed in this question.
如本问题所述,在 JavaScript 中解构为动态命名的变量是不可能的。
To set keys dynamically, you can use reduce function without mutating object as follows:
要动态设置键,您可以使用 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)
Should note that you're creating a new object on every iteration though instead of updating a single clone. – mpen
应该注意的是,您在每次迭代时都会创建一个新对象,而不是更新单个克隆。– 笔
below is a version using reduce with single clone (updating initial value passed in to reduce).
下面是使用带有单个克隆的 reduce 的版本(更新传入 reduce 的初始值)。
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)