如何编写一个函数,在ES6中以最紧凑的方式只占用少量属性?
我已经提出了使用解构+简化对象文字的解决方案,但我不喜欢在代码中重复字段列表。
是否有更纤薄的解决方案?
(v) => {
let { id, title } = v;
return { id, title };
}
答案 0 :(得分:106)
虽然它不会重复字段列表,但这里有些更苗条。它使用"参数解构"避免需要v
参数。
({id, title}) => ({id, title})
@ EthanBrown的解决方案更为通用。这是一个更惯用的版本,它使用Object.assign
和计算属性([p]
部分):
function pick(o, ...props) {
return Object.assign({}, ...props.map(prop => ({[prop]: o[prop]})));
}
如果我们想保留属性'属性,例如configurable
和getter和setter,同时也省略了不可枚举的属性,然后:
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)})))
);
}
答案 1 :(得分:41)
我认为没有办法让它比你的回答(或者torazburo)更紧凑,但基本上你要做的就是模仿{{ 3}}。在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');
答案 2 :(得分:18)
解决这个问题的方法是翻转所采用的方法:不是从原始对象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"}

答案 3 :(得分:10)
使用逗号运算符的简短解决方案:
const pick = (O, ...K) => K.reduce((o, k) => (o[k]=O[k], o), {})
答案 4 :(得分:7)
TC39's object rest/spread properties proposal会让这个很漂亮:
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
z; // { a: 3, b: 4 }
(它确实存在创建您可能不需要的x
和y
变量的缺点。)
答案 5 :(得分:1)
我与Ethan Brown的解决方案类似,但更短 - 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" }
答案 6 :(得分:1)
一种方法可能是使用destructuring
将属性分配给空对象。
let person = {
fname:'tom',
lname:'jerry',
aage:100
}
let newPerson = {};
({fname: newPerson.fname, lname: newPerson.lname} = person);
console.log(newPerson);
答案 7 :(得分:1)
当前有一个strawman proposal用于改进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年7月,但仍为Stage 0的草稿,表明作者可能已放弃或遗忘了它。
我能想到的最简洁的速记涉及ancient language feature,没人再使用了:
Object.assign(target, {...(o => {
with(o) return { id, title };
})(source)});
在严格模式下禁止使用 with
语句,这使得99.999%的现代JavaScript都无法使用此方法。有点遗憾,因为这是我发现的with
功能的唯一中途使用。 ?
答案 8 :(得分: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' }
答案 9 :(得分:0)
ES6是撰写问题时的最新规范。如this answer中所述,ES2019中的密钥选择比ES6中的密钥选择显着缩短:
Object.fromEntries(
Object.entries(obj)
.filter(([key]) => ['foo', 'bar'].includes(key))
)
答案 10 :(得分: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}