单行从 ES 6 中的对象中获取一些属性

IT技术 javascript ecmascript-6 ecmascript-harmony destructuring ecmascript-next
2021-01-13 21:10:50

如何编写一个函数,在 ES6 中以最紧凑的方式只需要几个属性?

我想出了使用解构 + 简化对象文字的解决方案,但我不喜欢在代码中重复字段列表。

有更精简的解决方案吗?

(v) => {
    let { id, title } = v;
    return { id, title };
}
6个回答

这是更精简的内容,尽管它并不能避免重复字段列表。它使用“参数解构”来避免对v参数的需要

({id, title}) => ({id, title})

(请参阅其他答案中的可运行示例)。

@EthanBrown 的解决方案更通用。这是它的一个更惯用的版本,它使用Object.assign, 和计算属性([p]部分):

function pick(o, ...props) {
    return Object.assign({}, ...props.map(prop => ({[prop]: o[prop]})));
}

如果我们想保留属性的属性,例如configurablegetter 和 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)})))
    );
}
对于您的第一个pick()实现,您还可以执行以下操作return props.reduce((r, prop) => (r[prop] = o[prop], r), {})
2021-03-21 21:10:50
得到一个错误:属性描述必须是一个对象:未定义。不应该filter(...).map(prop => ({[prop]: get(prop)})))吗?
2021-03-23 21:10:50
当对象中不存在属性时,您将获得undefined. 有时这很重要。除此之外,好主意。
2021-03-24 21:10:50
+1 很好的答案,虎三郎;谢谢你让我知道Object.assignes6 就像一棵圣诞树,下面有这么多礼物我还在假期几个月后寻找礼物
2021-03-31 21:10:50
不幸的是,pick 版本在 flow 或 typescript 中不会是类型安全的。如果您想要类型安全,则无法绕过原始对象的解构分配,然后将每个分配给一个新对象。
2021-04-03 21:10:50

我认为没有任何方法可以使它比您的答案(或 torazburo 的答案)更紧凑,但基本上您要做的是模拟Underscore 的pickoperation在 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');
json 数组呢!
2021-03-21 21:10:50
你为什么使用hasOwnProperty如果字段是手工选择的,evenin似乎更合适;尽管我会完全省略检查并让它们默认为undefined.
2021-03-28 21:10:50
Bergi,这是一个合理的观点......我只是认为原型链上的属性(而不是方法)很奇怪和“臭”(因为它们是代码气味),我更喜欢默认情况下将它们过滤掉。如果有一个应用程序需要原型属性,那么...可以有一个选项。
2021-03-31 21:10:50
(耸肩)我觉得这对你的解决方案的回答;没有更精简的通用解决方案(torazaburo 的解决方案消除了多余的冗长,但基本问题——所有属性名称都必须写两次——意味着它不会比您的解决方案更好地扩展)。我的解决方案至少可以很好地扩展......pick一次正确的功能,你可以选择你想要的任意数量的属性,它不会使它们翻倍。
2021-04-06 21:10:50
谢谢。这不是我的问题的答案,而是非常好的补充。
2021-04-07 21:10:50

解决这一问题的技巧是将所采用的方法颠倒过来:不是从原始对象开始,而是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"}

或者...

const filtered = ['id', 'name'].reduce((result, key) => ({
    ...result, 
    [key]: orig[key] 
}), {});

console.log(filtered); // Object {id: 123456789, name: "test"}

使用逗号运算符的一个更短的解决方案:

const pick = (O, ...K) => K.reduce((o, k) => (o[k]=O[k], o), {})

console.log(
  pick({ name: 'John', age: 29, height: 198 }, 'name', 'age')
)  

如何使用这个?你能提供一个例子吗?
2021-03-30 21:10:50
它就像pick这个线程中的其他函数一样工作pick({ name: 'John', age: 29, height: 198 }, 'name', 'age')
2021-03-31 21:10:50

TC39 的对象休息/传播属性提案将使这非常巧妙:

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
z; // { a: 3, b: 4 }

(它确实有创建您可能不需要xy变量的缺点。)

这是 的一种方便形式omit,但不是pick
2021-03-12 21:10:50
我很想看到一个与 ES 提案完全相反的变体: let { a, b } as z = { x: 1, y: 2, a: 3, b: 4 }
2021-04-02 21:10:50