JavaScriptで、オブジェクトにメンバーを条件付きで追加するにはどうすればよいですか?


387

条件付きでメンバーを追加したオブジェクトを作成したいと思います。簡単なアプローチは次のとおりです。

var a = {};
if (someCondition)
    a.b = 5;

今、私はより慣用的なコードを書きたいと思います。やっています:

a = {
    b: (someCondition? 5 : undefined)
};

しかし、現在、その値がのbメンバーaですundefined。これは望ましい結果ではありません。

便利な解決策はありますか?

更新

複数のメンバーがいる一般的なケースを処理できるソリューションを探しています。

a = {
  b: (conditionB? 5 : undefined),
  c: (conditionC? 5 : undefined),
  d: (conditionD? 5 : undefined),
  e: (conditionE? 5 : undefined),
  f: (conditionF? 5 : undefined),
  g: (conditionG? 5 : undefined),
 };

23
はいあります; コードの最初のビット。
Paolo Bergantino 2012

6
慣用的なJavaScriptなどがあるかどうかわからない...
Michael Berkowski

それは実際に重要ですか?を定義したことがない場合でもa.b、取得a.bundefinedとにかく戻ります。
Teemu

6
@Teemu:in演算子を使用するときに問題になる可能性があります。

1
今のところ、リテラルオブジェクトに条件付きプロパティを設定する方法はありませんが、ES7で追加したい場合、これは特にサーバー側プログラミングで非常に便利です。
Ali

回答:


118

純粋なJavascriptでは、最初のコードスニペットほど慣用的なものは考えられません。

ただし、jQueryライブラリの使用が問題にならない場合は、ドキュメントに記載されているように、$。extend()が要件を満たす必要があります。

未定義のプロパティはコピーされません。

したがって、次のように書くことができます。

var a = $.extend({}, {
    b: conditionB ? 5 : undefined,
    c: conditionC ? 5 : undefined,
    // and so on...
});

そして、(あればあなたが期待する結果を得ることconditionBfalse、そのb中には存在しませんa)。


21
jQueryを必要としない、はるかに優れたメソッドがあります。ジェイミー・ヒルの答えを見てください。
Andrew Rasmussen

13
@Andrew、その答えには、私が書いた時点では存在しなかったES6が必要です。
フレデリックハミディ2016年

nullは同じように機能しますか?それとも未定義でなければなりませんか?
Aous1000

jQueryを使用し、この3項条件はオブジェクトからプロパティを削除しないため、これは実際には間違った答えです。これは、プロパティを未定義として設定するだけです。これを行う正しい方法については、@ lagistosの回答を参照してください
Alexander Kim

はい、以下のJamieの回答を確認してください:stackoverflow.com/a/40560953/10222449
MadMac

871

@InspiredJWはES5でそれを行ったと思います。@ trincotが指摘したように、es6を使用する方がより良いアプローチです。ただし、spread演算子と論理AND短絡評価を使用して、もう少し砂糖を追加できます。

const a = {
   ...(someCondition && {b: 5})
}

2
私はこれが正しいと確信していません、提案は述べNull/Undefined Are Ignoredています、それfalseは無視されているとは言いません。現在、トランスパイラーはこれを許可していますが、準拠していますか?次のものはそうあるべき{...someCondition ? {b: 5} : null}ですが、それほどコンパクトではありません。
ベンジャミンドベル2017

23
これは普及の提案をした人々に有効であるかどうか尋ねました、そして彼らはこれは問題ないと言いました github.com/tc39/proposal-object-rest-spread/issues/45、cc @BenjaminDobell
김민준

73
@AlanHスプレッド演算子はObject.assign、&&演算子の短縮形に似ており、優先順位が低くなっています。プロパティなしの値(ブール値、null、未定義、数値)を無視し、オブジェクトのすべてのプロパティを所定の位置に追加します...。覚えている&&それ以外の場合は真、またはfalseの場合、オペレータが正しい値を返します。したがって、someConditiontrueの場合{b : 5}...演算子に渡され、その結果、プロパティがvalue に追加baれます5。is someConditionはfalseでfalse...オペレーターに渡されます。結果は何も追加されません。それは賢いです。大好きです。
フェリックス黒髪

11
すばらしい答えですが、条件と結果のオブジェクトを括弧内に配置すると、この例の可読性が大幅に向上します。JSオペレーターの優先順位を誰もが覚えているわけではありません。
神経伝達物質2017

6
他の唯一の問題は、これを偽のブール値に使用できないことです。
ggb667

92

EcmaScript2015を使用すると、Object.assign以下を使用できます。

Object.assign(a, conditionB ? { b: 1 } : null,
                 conditionC ? { c: 2 } : null,
                 conditionD ? { d: 3 } : null);

いくつかの備考:

さらに簡潔

(@Jamieは尖ったアウトを持っているとして)falsy値は全く独自の列挙可能な特性を持っていないとして、(次のようにさらに第二の点を取ると、あなたはそれを短縮することができfalse0NaNnullundefined''を除きますdocument.all):

Object.assign(a, conditionB && { b: 1 },
                 conditionC && { c: 2 },
                 conditionD && { d: 3 });


1
私は最初の解決策を好む:何が起こっているのかを理解するのが簡単–プリミティブ値で何が起こるかわからない(少なくとも仕様を見ない限り)。
アクセルラウシュマイヤー2017年

1
三元論理を簡略化する省略表現が大好きです。これはまさに私が必要としたものです。ありがとうございました!
theUtherSide 2018年

80
const obj = {
   ...(condition) && {someprop: propvalue},
   ...otherprops
}

ライブデモ:

const obj = {
  ...(true) && {someprop: 42},
  ...(false) && {nonprop: "foo"},
  ...({}) && {tricky: "hello"},
}

console.log(obj);


7
このコードスニペットは問題を解決する可能性がありますが、説明を含めると、投稿の質を高めるのに役立ちます。あなたは将来の読者のための質問に答えていることを覚えておいてください、そしてそれらの人々はあなたのコード提案の理由を知らないかもしれません。
Ralf Stubner、2018

1
この回答は、2年前のJamie Hillの回答に何を追加しますか?
Dan Dascalescu

condが一致しない場合、これは未定義を返します。
Mustkeem K

2
これは機能し、IMOの他のどの回答よりも構文が優れています。
Seph Reed

1
簡単な説明は次のようになります: "..."スプレッド演算子はオブジェクトリテラルを分解し、それを "obj"に追加します。たとえば、この場合...(true)&& {someprop:42}、分解される用語全体は「(true)&& {someprop:42}」、この場合、ブール値はtrueであり、用語は{someprop:42}を生成するだけで、これは分解されてobjに追加されます。代わりにブール値がfalseの場合、用語は単にfalseになり、何も分解されず、objに追加されません
Qiong Wu

50

(ここで提案されているように)ブール値で拡散構文を使用することは有効な構文ではありません。Spreadは、イテラブルでのみ使用できます。

私は以下を提案します:

const a = {
   ...(someCondition? {b: 5}: {} )
}

2
@HossamMourad、提案されたコードは2年以上前に投稿された回答ですでに使用されているため、使用しないでください。そして、最初の発言は偽です。これは有効な構文です{...false}
。– trincot

1
@イタイ、これは真実ではありません。プリミティブ値は、spread構文で使用するとラップされます。{...false}有効な構文です。
トリンコット

@trincot、リファレンスを提供してもらえますか?
板井ノーム

3
EcmaScript 2018言語仕様のセクション12.2.6(.8)CopyDataPropertiesは、値に対して実行されることを指定しています(falseこの場合)。これにはプリミティブのボックス化が含まれます(セクション7.3.23、7.1.13)。MDNへのリンクでは、この "例外"が括弧で囲まれています。
トリンコット

参考として、この同じトピックについて詳しく説明しているこの投稿も参照してください。
トリンコット

26

拡張オブジェクトプロパティの使用についてはどうですか。それが真実である場合にのみプロパティを設定します。例:

[isConditionTrue() && 'propertyName']: 'propertyValue'

したがって、条件が満たされない場合、優先プロパティは作成されないため、破棄できます。参照:http : //es6-features.org/#ComputedPropertyNames

更新: 条件付きでオブジェクトリテラルと配列内にエントリを追加することに関する彼のブログ記事(http://2ality.com/2017/04/conditional-literal-entries.html)のAxel Rauschmayerのアプローチに従うのがさらに良いです:

const arr = [
  ...(isConditionTrue() ? [{
    key: 'value'
  }] : [])
];

const obj = {
  ...(isConditionTrue() ? {key: 'value'} : {})
};

かなり助けてくれました。


1
ほとんど動作します。問題は、余分なfalseキーを追加することです。たとえば、 {[true && 'a']: 17, [false && 'b']: 42}{a:17, false: 42}
次のとおり

3
より簡潔な方法を見つけました: ...isConditionTrue() && { propertyName: 'propertyValue' }
Dimitri Reifschneider '22

より良い方法:...(isConditionTrue()?{key: 'value'}:{})
Dimitri Reifschneider

Axel Rauschmayerのブログリンクがこの答えを示しています。記事の「... insertIf(cond、 'a')」の例は、まさに私が探していたものです。ありがとう
ジョセフ・シンプソン


5

目的がオブジェクトを自己完結的に表示し、1組のブレース内に収めることである場合は、次のように試すことができます。

var a = new function () {
    if (conditionB)
        this.b = 5;

    if (conditionC)
        this.c = 5;

    if (conditionD)
        this.d = 5;
};

5

このサーバーサイド(jqueryなし)を実行する場合は、lodash 4.3.0を使用できます。

a = _.pickBy({ b: (someCondition? 5 : undefined) }, _.negate(_.isUndefined));

そして、これはlodash 3.10.1を使用して動作します

a = _.pick({ b: (someCondition? 5 : undefined) }, _.negate(_.isUndefined));

ES6ではlodashは必要ありません。
Dan Dascalescu

5
var a = {
    ...(condition ? {b: 1} : '') // if condition is true 'b' will be added.
}

これが条件に基づいてエントリを追加する最も効率的な方法であることを願っています。オブジェクトリテラル内にエントリを条件付きで追加する方法の詳細については。


3
[...condition?'':['item']]これにより、文字列アイテムが配列に追加されます
Wayou

この回答は、1年前のJamie Hillの回答よりも優れてます。
Dan Dascalescu

1
@DanDascalescuジェイミーヒルの答えは私の答えよりも優れています。私はそのように考えていなかったので、以前は三項演算子の人でした。
Madhankumar

4

これは長い間回答されてきましたが、他のアイデアを見て、私はいくつかの興味深い派生物を思いつきました:

未定義の値を同じプロパティに割り当て、後で削除する

匿名コンストラクタを使用してオブジェクトを作成し、最後に削除する同じダミーメンバーに常に未定義のメンバーを割り当てます。これにより、メンバーごとに1行(あまり複雑ではない)と最後に1行追加されます。

var a = new function() {
    this.AlwaysPresent = 1;
    this[conditionA ? "a" : "undef"] = valueA;
    this[conditionB ? "b" : "undef"] = valueB;
    this[conditionC ? "c" : "undef"] = valueC;
    this[conditionD ? "d" : "undef"] = valueD;
    ...
    delete this.undef;
};

4

条件なしですべての未定義の値を追加し、を使用JSON.stringifyしてそれらをすべて削除できます。

const person = {
  name: undefined,
  age: 22,
  height: null
}

const cleaned = JSON.parse(JSON.stringify(person));

// Contents of cleaned:

// cleaned = {
//   age: 22,
//   height: null
// }

2

私はこれをします

var a = someCondition ? { b: 5 } : {};

1行のコードバージョンで編集


条件がfalseの場合、aはnudefinedであり、これは正しくありません。
bingjie2680 2012

@ bingjie2680 someConditionがfalseの場合それがどうあるべきか明確ではありません。ただ思いました。これは:/a = undefinedreturn { b: undefined };
jwchang

@ bingjie2680その後return {};else一部になるはずです
jwchang

1
それは本当にあなたがすることではありません...それですか?つまり、リテラル構文全体を条件付きにしたとしても、なぜ条件演算子を使用しないのでしょうか。a = condition ? {b:5} : undefined;

3
おめでとうございます。3つの完全にシンプルなラインをゲインなしの7ライン関数に変更しました。いいえ、無名関数を使用してもメリットはありません。

2

lodashライブラリを使用すると、_。omitByを使用できます

var a = _.omitBy({
    b: conditionB ? 4 : undefined,
    c: conditionC ? 5 : undefined,
}, _.IsUndefined)

これは、オプションのリクエストがある場合に便利です

var a = _.omitBy({
    b: req.body.optionalA,  //if undefined, will be removed
    c: req.body.optionalB,
}, _.IsUndefined)

0

条件付きでメンバーを追加するあなたの最初のアプローチは完全に素晴らしいと思います。の値を持つのメンバーbを希望しないことに本当に同意しません。演算子でループを使用してチェックを追加するのは簡単です。しかし、とにかく、メンバーをフィルターで除外する関数を簡単に作成できます。aundefinedundefinedforinundefined

var filterUndefined = function(obj) {
  var ret = {};
  for (var key in obj) {
    var value = obj[key];
    if (obj.hasOwnProperty(key) && value !== undefined) {
      ret[key] = value;
    }
  }
  return ret;
};

var a = filterUndefined({
  b: (conditionB? 5 : undefined),
  c: (conditionC? 5 : undefined),
  d: (conditionD? 5 : undefined),
  e: (conditionE? 5 : undefined),
  f: (conditionF? 5 : undefined),
  g: (conditionG? 5 : undefined),
});

delete演算子を使用してオブジェクトを編集することもできます。


0

オブジェクトに包み込む

このようなものは少しきれいです

 const obj = {
   X: 'dataX',
   Y: 'dataY',
   //...
 }

 const list = {
   A: true && 'dataA',
   B: false && 'dataB',
   C: 'A' != 'B' && 'dataC',
   D: 2000 < 100 && 'dataD',
   // E: conditionE && 'dataE',
   // F: conditionF && 'dataF',
   //...
 }

 Object.keys(list).map(prop => list[prop] ? obj[prop] = list[prop] : null)

配列にラップする

または、Jamie Hillの方法を使用し、条件のリストが非常に長い場合は、...構文を複数回記述する必要があります。少しきれいにするには、それらを配列にラップしてreduce()から、を使用してそれらを単一のオブジェクトとして返すことができます。

const obj = {
  X: 'dataX',
  Y: 'dataY',
  //...

...[
  true && { A: 'dataA'},
  false && { B: 'dataB'},
  'A' != 'B' && { C: 'dataC'},
  2000 < 100 && { D: 'dataD'},
  // conditionE && { E: 'dataE'},
  // conditionF && { F: 'dataF'},
  //...

 ].reduce(( v1, v2 ) => ({ ...v1, ...v2 }))
}

またはmap()関数を使用して

const obj = {
  X: 'dataX',
  Y: 'dataY',
  //...
}

const array = [
  true && { A: 'dataA'},
  false &&  { B: 'dataB'},
  'A' != 'B' && { C: 'dataC'},
  2000 < 100 && { D: 'dataD'},
  // conditionE && { E: 'dataE'},
  // conditionF && { F: 'dataF'},
  //...

 ].map(val => Object.assign(obj, val))

0

これは私が思いつくことができる最も簡潔な解決策です:

var a = {};
conditionB && a.b = 5;
conditionC && a.c = 5;
conditionD && a.d = 5;
// ...

-1

lodashライブラリを使用すると、_。mergeを使用できます

var a = _.merge({}, {
    b: conditionB ? 4 : undefined,
    c: conditionC ? 5 : undefined,
})
  1. conditionBがfalse&conditionCがのtrue場合、a = { c: 5 }
  2. conditionBとconditionCの両方がのtrue場合、a = { b: 4, c: 5 }
  3. conditionBとconditionCの両方がのfalse場合、a = {}

別の結果が得られます。私は使用していlodash@^4.0.0ます。undefined私のケースに含まれています。
JohnnyQ 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.