167

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

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

有没有更苗条的解决方案?

(v) => {
    let { id, title } = v;
    return { id, title };
}
4

11 回答 11

141

这里有一些更苗条的东西,尽管它不会避免重复字段列表。它使用“参数解构”来避免对v参数的需要。

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

(请参阅this other answer中的可运行示例)。

@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)})))
    );
}
于 2014-08-28T17:22:01.523 回答
44

我认为没有任何方法可以使它比您的答案(或 torazburo 的)更紧凑,但基本上您要做的是模仿Underscore 的pick操作。在 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');
于 2014-09-14T16:19:04.093 回答
22

以单线方式解决此问题的诀窍是翻转所采用的方法: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"}
于 2017-01-20T14:17:16.100 回答
14

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

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

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

于 2017-12-15T19:12:21.843 回答
8

TC39 的 object rest/spread properties 提案将使这变得非常漂亮:

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

(它确实有创建你可能不需要的x和变量的缺点。)y

于 2017-05-03T18:29:01.250 回答
6

ES6 是编写问题时的最新规范。正如这个答案中所解释的,在 ES2019 中的关键选择比在 ES6 中要短得多:

Object.fromEntries(
  Object.entries(obj)
  .filter(([key]) => ['foo', 'bar'].includes(key))
)
于 2019-06-25T10:26:55.040 回答
4

您可以使用对象解构从现有对象中解压缩属性并将它们分配给具有不同名称的变量- 一个新的、最初为空的对象的字段。

const person = {
  fname: 'tom',
  lname: 'jerry',
  aage: 100,
}

let newPerson = {};

({fname: newPerson.fname, lname: newPerson.lname} = person);

console.log(newPerson);

于 2019-05-01T04:01:14.280 回答
2

目前有一个关于改进 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 月,目前仍处于第 0 阶段的草稿,这表明作者可能已经放弃或忘记了它。

ES5 及更早版本(非严格模式)

我能想到的最简洁的速记涉及一个不再使用的古老语言功能:

Object.assign(target, {...(o => {
    with(o) return { id, title };
})(source)});

with语句在严格模式下是被禁止的,这使得这种方法对于 99.999% 的现代 JavaScript 来说毫无用处。有点遗憾,因为这是我为该功能找到的唯一一个中规中矩的用途with

于 2019-06-13T23:52:00.147 回答
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" }
于 2016-08-04T16:45:23.523 回答
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' }
于 2017-09-16T18:29:58.793 回答
-1

受到https://stackoverflow.com/users/865693/shesek的 reduce 方法的启发:

const pick = (orig, keys) => keys.reduce((acc, key) => ({...acc, [key]: orig[key]}), {})

甚至使用逗号运算符(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator)稍微短一些

const pick = (obj, keys) => keys.reduce((acc, key) => ((acc[key] = obj[key]), acc), {});

用法:

pick({ model : 'F40', manufacturer: 'Ferrari', productionYear: 1987 }, 'model', 'productionYear') 结果是: {model: "F40", productionYear: 1987}

于 2019-08-15T11:11:09.067 回答