两种常见的方法是 destructuring 和传统的类似 Lodash 的 pick/omit 实现。它们之间的主要实际区别在于,解构需要一个键列表是静态的,不能省略它们,包括不存在的选择键,即它是包容性的。这可能是可取的,也可能是不可取的,并且不能针对解构语法进行更改。
给定:
var obj = { 'foo-bar': 1, bar: 2, qux: 3 };
常规选择foo-bar、bar、baz键的预期结果:
{ 'foo-bar': 1, bar: 2 }
inclusive 采摘的预期结果:
{ 'foo-bar': 1, bar: 2, baz: undefined }
解构
解构语法允许使用函数参数或变量对对象进行解构和重组。
限制是键列表是预定义的,它们不能作为字符串列出,如问题中所述。如果键是非字母数字的,解构会变得更加复杂,例如foo-bar.
好处是它是 ES6 自然的高性能解决方案。
缺点是键列表是重复的,如果列表很长,这会导致代码冗长。由于在这种情况下解构复制了对象文字语法,因此可以按原样复制和粘贴列表。
IIFE
let subset = (({ 'foo-bar': foo, bar, baz }) => ({ 'foo-bar': foo, bar, baz }))(obj);
临时变量
let { 'foo-bar': foo, bar, baz } = obj;
let subset = { 'foo-bar': foo, bar, baz };
字符串列表
根据问题的需要,所选键的任意列表由字符串组成。这允许不预定义它们并使用包含键名的变量,['foo-bar', someKey, ...moreKeys]。
ECMAScript 2017 有 Object.entries 和 Array.prototype.includes,ECMAScript 2019 有 Object.fromEntries,它们可以在需要时进行 polyfill。
单线
考虑到要选择的对象包含额外的键,通常从列表中迭代键而不是对象键更有效,如果需要省略键,反之亦然。
选择(ES5)
var subset = ['foo-bar', 'bar', 'baz']
.reduce(function (obj2, key) {
if (key in obj) // line can be removed to make it inclusive
obj2[key] = obj[key];
return obj2;
}, {});
省略(ES5)
var subset = Object.keys(obj)
.filter(function (key) {
return ['baz', 'qux'].indexOf(key) < 0;
})
.reduce(function (obj2, key) {
obj2[key] = obj[key];
return obj2;
}, {});
选择(ES6)
const subset = ['foo-bar', 'bar', 'baz']
.filter(key => key in obj) // line can be removed to make it inclusive
.reduce((obj2, key) => (obj2[key] = obj[key], obj2));
省略(ES6)
const subset = Object.keys(obj)
.filter(key => ['baz', 'qux'].indexOf(key) < 0)
.reduce((obj2, key) => (obj2[key] = obj[key], obj2));
选择(ES2019)
const subset = Object.fromEntries(
['foo-bar', 'bar', 'baz']
.filter(key => key in obj) // line can be removed to make it inclusive
.map(key => [key, obj[key]])
);
省略(ES2019)
const subset = Object.fromEntries(
Object.entries(obj)
.filter(([key]) => !['baz', 'qux'].includes(key))
);
可重用函数
单行可以表示为类似于 Lodash pick 或 omit 的可重用辅助函数,其中键列表通过参数传递,pick(obj, 'foo-bar', 'bar', 'baz')。
const pick = (obj, ...keys) => Object.fromEntries(
keys
.filter(key => key in obj)
.map(key => [key, obj[key]])
);
const inclusivePick = (obj, ...keys) => Object.fromEntries(
keys.map(key => [key, obj[key]])
);
const omit = (obj, ...keys) => Object.fromEntries(
Object.entries(obj)
.filter(([key]) => !keys.includes(key))
);