ES 6のオブジェクトからいくつかのプロパティを取得するためのワンライナー


153

ES6で最もコンパクトな方法で少数の属性のみを取る関数をどのように作成できますか?

解体+単純化されたオブジェクトリテラルを使用した解決策を考え出しましたが、フィールドのリストがコード内で繰り返されるのが嫌いです。

さらにスリムなソリューションはありますか?

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

回答:


124

これはよりスリムなものですが、フィールドのリストを繰り返すことは避けられません。「パラメータのデストラチャリング」を使用して、vパラメータの必要性を回避します。

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

(この他の回答の実行可能な例を参照してください)。

@EthanBrownのソリューションはより一般的です。以下は、のより慣用的なバージョンでObject.assignあり、計算されたプロパティ([p]部分)を使用します。

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

configurableおよびゲッターやセッターなどのプロパティの属性を保持し、同時に列挙できないプロパティを省略したい場合は、次のようにします。

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)})))
    );
}

10
いい答え、トラザブロ+1。私に知らせてくれてありがとうObject.assign。ES6は、その下に非常に多くのプレゼントをクリスマスツリーのようなものです私はまだ休日後のギフトの数ヶ月探しています
イーサン・ブラウン

エラーが発生しました:プロパティの説明はオブジェクトでなければなりません:未定義。そうじゃないのfilter(...).map(prop => ({[prop]: get(prop)})))
エンドレス

最初のpick()実装では、次のようなこともできますreturn props.reduce((r, prop) => (r[prop] = o[prop], r), {})
Patrick Roberts

残念ながら、そのバージョンのpickは、フローまたはタイプスクリプトでタイプセーフではありません。タイプセーフが必要な場合は、元のオブジェクトの割り当てを分解してから、それぞれを新しいオブジェクトに割り当てる方法はありません。
duhseekoh

プロパティがオブジェクトに存在しない場合は、を取得しundefinedます。時にはそれが重要です。それ以外はいいアイデアです。
x-yuri

43

私はあなたの答え(または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

7
(肩をすくめる)それあなたの解決策の答えだと思います。よりスリムな一般的な解決策はありません(torazaburoの解決策は余分な動詞から削除されますが、本質的な問題-すべてのプロパティ名を2回記述する必要がある-は、ソリューションよりも優れたスケーリングを行わないことを意味します)。私のソリューションは少なくとも適切にスケーリングします... pick関数を1回正しく実行すれば、必要な数のプロパティを選択できますが、プロパティが2倍になることはありません。
Ethan Brown

1
なぜ使うのhasOwnProperty?フィールドが手動で選択されている場合は、inさらに適切であるように見えます。ただし、チェックを完全に省略して、デフォルトのに設定しundefinedます。
Bergi 2015年

Bergi、それは妥当なポイントです...私はプロトタイプチェーンのプロパティ(メソッドではなく)を奇妙で「臭い」があると考えています(コードのにおいのように)、デフォルトでそれらを除外することを好みます。プロトタイプのプロパティを必要とするアプリケーションがある場合、まあ...そのためのオプションがある可能性があります。
イーサンブラウン

json配列はどうですか?
リズワンパテル2017

19

これをワンライナーとして解決する秘訣は、取られたアプローチを逆origにすることです。元のオブジェクトから開始する代わりに、抽出したいキーから開始することができます。

使用してArray#reduce1は次にとして渡される空のオブジェクト上の各必要な鍵格納することができる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"}


11

コンマ演算子を使用した少し短いソリューション:

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

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


これを使用する方法?例を提供できますか?
Tomas M

1
それはちょうど、他のように動作しますpick:このスレッド内の機能pick({ name: 'John', age: 29, height: 198 }, 'name', 'age')
shesek

8

TC39のオブジェクトレスト/スプレッドプロパティの提案により、これはかなり滑らかになります。

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

(それはあなたが必要としないかもしれない変数xy変数を作成することの欠点を持っています。)


33
これはの便利な形式ですomitが、そうではありませんpick
キリルイド2017年

5
:私は、ESの提案として本の正反対を行うバリアント見てみたいlet { a, b } as z = { x: 1, y: 2, a: 3, b: 4 }
gfullam

3

オブジェクトの構造化を使用して、既存のオブジェクトからプロパティをアンパックし、それらを異なる名前の変数(新しい、最初は空のオブジェクトのフィールド)に割り当てることができます。

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

let newPerson = {};

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

console.log(newPerson);


(インデックス):36
キャッチされないSyntaxError

@Remzesはこれをどこでどのように実行しているのかわかりませんが、SOコードエディターやChrome開発ツールでうまく機能します。
Saksham

私はjsfiddleを使用しました
Remzes

私はあなたの答えを少し改善しましたが、OPが要求したものに対して、それはまだ冗長すぎます。フィールド名だけでなく、新しいオブジェクトの名前も繰り返されます。
Dan Dascalescu

3

ES6は、質問が書かれたときの最新の仕様でした。この回答で説明されているように、キーのピッキングはES2019のほうがES6よりも大幅に短くなっています。

Object.fromEntries(
  Object.entries(obj)
  .filter(([key]) => ['foo', 'bar'].includes(key))
)

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ステートメントは厳格モードでは禁止されているため、このアプローチは最新のJavaScriptの99.999%では役に立たなくなります。これは私がこのwith機能で見つけた唯一の適切な使用法であるため、少し残念です。😀


1

私はイーサン・ブラウンの解決策に似ていますが、もっと短いです- 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" }

1
反対票を投じる理由は何ですか?うまくいきませんか?
Alexandr Priezzhev 2017年

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' }

0

https://stackoverflow.com/users/865693/shesekのreduceアプローチに触発されました:

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}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.