簡體   English   中英

JavaScript,如何給一個object有條件的加成員?

[英]In JavaScript, how to conditionally add a member to an object?

我想創建一個 object 並有條件地添加一個成員。 簡單的方法是:

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

現在,我想寫一個更地道的代碼。 我在嘗試:

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

但是現在, ba的成員,其值為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),
 };

我認為@InspiredJW 是用 ES5 做到的,正如@trincot 所指出的,使用 es6 是一種更好的方法。 但是我們可以通過使用擴展運算符和邏輯與短路評估來添加更多的糖:

const a = {
   ...(someCondition && {b: 5})
}
const obj = {
   ...(condition) && {someprop: propvalue},
   ...otherprops
}

現場演示:

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

在純 Javascript 中,我想不出比您的第一個代碼片段更慣用的東西了。

但是,如果使用 jQuery 庫不是不可能的,那么$.extend()應該滿足您的要求,因為正如文檔所述:

未定義的屬性不會被復制。

因此,您可以編寫:

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

並獲得您期望的結果(如果conditionBfalse ,則b將不存在於a中)。

我建議如下:

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

使用 EcmaScript2015,您可以使用Object.assign

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

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

一些備注:

  • Object.assign就地修改了第一個參數,但它也返回了更新后的對象:因此您可以在更大的表達式中使用此方法,以進一步操作該對象。
  • 您可以傳遞undefined{}而不是null ,但結果相同。 您甚至可以提供0代替,因為原始值被包裝,並且Number沒有自己的可枚舉屬性

更簡潔

進一步考慮第二點,您可以將其縮短如下(正如@Jamie 指出的那樣),因為虛假值沒有自己的可枚舉屬性( false0NaNnullundefined'' ,除了document.all ):

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

 var a, conditionB, conditionC, conditionD; conditionC = "this is truthy"; conditionD = NaN; // falsy a = {}; Object.assign(a, conditionB && { b: 1 }, conditionC && { c: 2 }, conditionD && { d: 3 }); console.log(a);

有條件地向對象添加成員

const trueCondition = true;
const falseCondition = false;
const obj = {
  ...(trueCondition && { student: 10 }),
  ...(falseCondition && { teacher: 2 }),
};

// { student: 10 }

性能測試

經典方法

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

VS

傳播算子方法

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

結果

經典方法要快得多,因此請考慮到語法糖化較慢。

testClassicConditionFulfilled(); // ~ 234.9 毫秒
testClassicConditionNotFulfilled(); // ~493.1ms
testSpreadOperatorConditionFulfilled(); // ~2649.4ms
testSpreadOperatorConditionNotFulfilled(); // ~2278.0ms

 function testSpreadOperatorConditionFulfilled() { const value = 5; console.time('testSpreadOperatorConditionFulfilled'); for (let i = 0; i < 200000000; i++) { let a = { ...(value && {b: value}) }; } console.timeEnd('testSpreadOperatorConditionFulfilled'); } function testSpreadOperatorConditionNotFulfilled() { const value = undefined; console.time('testSpreadOperatorConditionNotFulfilled'); for (let i = 0; i < 200000000; i++) { let a = { ...(value && {b: value}) }; } console.timeEnd('testSpreadOperatorConditionNotFulfilled'); } function testClassicConditionFulfilled() { const value = 5; console.time('testClassicConditionFulfilled'); for (let i = 0; i < 200000000; i++) { let a = {}; if (value) ab = value; } console.timeEnd('testClassicConditionFulfilled'); } function testClassicConditionNotFulfilled() { const value = undefined; console.time('testClassicConditionNotFulfilled'); for (let i = 0; i < 200000000; i++) { let a = {}; if (value) ab = value; } console.timeEnd('testClassicConditionNotFulfilled'); } testClassicConditionFulfilled(); // ~ 234.9ms testClassicConditionNotFulfilled(); // ~493.1ms testSpreadOperatorConditionFulfilled(); // ~2649.4ms testSpreadOperatorConditionNotFulfilled(); // ~2278.0ms

更簡化,

const a = {
    ...(condition && {b: 1}) // if condition is true 'b' will be added.
}

使用增強的對象屬性怎么樣,並且只在它是真實的情況下設置屬性,例如:

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

因此,如果不滿足條件,則不會創建首選屬性,因此您可以丟棄它。 請參閱: http ://es6-features.org/#ComputedPropertyNames

更新:最好遵循 Axel Rauschmayer 在他的博客文章中關於有條件地在對象文字和數組中添加條目的方法( http://2ality.com/2017/04/conditional-literal-entries.html ):

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

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

對我幫助很大。

更好的答案:

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

簡單的 ES6 解決方案

帶有 (&) 的單一條件

 const didIPassExam = true const study = { monday: 'writing', tuesday: 'reading', /* check conditionally and if true, then add wednesday to study */...(didIPassExam && {wednesday: 'sleep happily'}) } console.log(study)

具有 (? :) 的雙重條件

 const score = 110 //const score = 10 const storage = { a:10, b:20, ...(score > 100? {c: 30}: {d:40}) } console.log(storage)

解釋

假設您有這樣的storage object

const storage = {
  a : 10,
  b : 20,
}

並且您想根據score有條件地為此添加道具

const score = 90

如果score大於100 ,您現在想將c:30添加到storage中。

如果分數小於100 ,那么您要將d:40添加到storage中。 你可以這樣做

const score = 110

const storage = {
  a:10,
  b:20,
  ...(score > 100  ? {c: 30} : {d:40}) 
}

上面的代碼給出了storage作為

{
  a: 10,
  b: 20,
  c: 30
}

如果score = 90

然后你得到storage作為

{
  a: 10,
  b: 20,
  d: 40
}

代碼筆示例

這可能是 ES6 中最短的解決方案

console.log({
   ...true && {foo: 'bar'}
})
// Output: {foo:'bar'}
console.log({
   ...false && {foo: 'bar'}
})
// Output: {}

我會這樣做

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

您可以無條件添加所有未定義的值,然后使用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
// }

如果目標是讓對象看起來是獨立的並且在一組大括號內,你可以試試這個:

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

    if (conditionC)
        this.c = 5;

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

這早就得到了回答,但是看着其他想法,我想出了一些有趣的衍生物:

為同一屬性分配未定義的值,然后將其刪除

使用匿名構造函數創建您的對象,並始終將未定義的成員分配給您在最后刪除的同一虛擬成員。 這將為每個成員提供一行(我希望不是太復雜)+ 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;
};

如果你希望做這個服務器端(沒有 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));
var a = {
    ...(condition ? {b: 1} : '') // if condition is true 'b' will be added.
}

我希望這是根據條件添加條目的有效方法。 有關如何有條件地在對象文字中添加條目的更多信息。

我用另一種選擇做了一個小基准測試 我喜歡從一些物體上去除“自重”。 通常是虛假值。

以下是本benny的結果:

干凈的

const clean = o => {
    for (const prop in o) if (!o) delete o[prop];
}

clean({ value });

傳播

let a = {
    ...(value && {b: value})
};

如果

let a = {};
if (value) {
    a.b = value;
}

結果

clean  :  84 918 483 ops/s, ±1.16%    | 51.58% slower    
spread :  20 188 291 ops/s, ±0.92%    | slowest, 88.49% slower    
if     : 175 368 197 ops/s, ±0.50%    | fastest

使用 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)

這是我能想到的最簡潔的解決方案:

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

我更喜歡,使用它的代碼,你可以運行這個代碼

const three = {
  three: 3
}

// you can active this code, if you use object `three is null`
//const three = {}

const number = {
  one: 1,
  two: 2,
  ...(!!three && three),
  four: 4
}

console.log(number);
const isAdult = true;

const obj = {
  ...(isAdult ? { age: 18 }: { age: 17}),
};

//>> { student: 18 }

我認為您第一種有條件地添加成員的方法非常好。 我真的不同意不希望 a 的成員b a值為undefined 使用帶有in運算符的for循環添加undefined檢查非常簡單。 但無論如何,您可以輕松編寫一個函數來過濾掉undefined的成員。

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運算符來編輯對象。

下面的代碼片段應該可以工作。

const a = {}

const conditionB = true;
const conditionC = true;
const conditionD = true;
const conditionE = true;

const b = {
  ...(conditionB && { b : 5}),
  ...(conditionC && { c : 5}),
  ...(conditionD && { d : 5}),
  ...(conditionE && { e : 5}),
 };

console.log(b);

我希望這有助於解決您的問題

 <body> <h1>GeeksforGeeks</h1> <p id="geeks"></p> <:-- Script to check array include object or not --> <script> var obj = {"geeks1",10: "geeks2",12} var arr = ["geeks1", "geeks2", "geeks3"; obj]. if(arr.filter(value=> value==obj).length > 0) document;write("true"). else document;write("false"); </script> </body>

使用 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 = {}

包裝成一個對象

像這樣的東西有點干凈

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

通過let定義一個 var 並分配新屬性

let msg = {
    to: "hito@email.com",
    from: "hifrom@email.com",
    subject: "Contact form",    
};

if (file_uploaded_in_form) { // the condition goes here
    msg.attachments = [ // here 'attachments' is the new property added to msg Javascript object
      {
        content: "attachment",
        filename: "filename",
        type: "mime_type",
        disposition: "attachment",
      },
    ];
}

現在msg變成

{
    to: "hito@email.com",
    from: "hifrom@email.com",
    subject: "Contact form",
    attachments: [
      {
        content: "attachment",
        filename: "filename",
        type: "mime_type",
        disposition: "attachment",
      },
    ]
}

在我看來,這是非常簡單易行的解決方案。

為了完整起見,如果要添加其他描述符,可以使用Object.defineProperty() 請注意,我特意添加了enumerable: true ,否則該屬性不會出現在console.log()中。 這種方法的優點是,如果要添加多個新屬性,還可以使用Object.defineProperties() (但是,這樣每個屬性都將依賴於相同的條件......)

 const select = document.getElementById("condition"); const output = document.getElementById("output"); let a = {}; let b = {}; select.onchange = (e) => { const condition = e.target.value === "true"; condition ? Object.defineProperty(a, "b", { value: 5, enumerable: true, }) : (a = {}); condition ? Object.defineProperties(b, { c: { value: 5, enumerable: true, }, d: { value: 6, enumerable: true, }, e: { value: 7, enumerable: true, }, }) : (b = {}); outputSingle.innerText = JSON.stringify(a); outputMultiple.innerText = JSON.stringify(b); };
 Condition: <select id="condition"> <option value="false">false</option> <option value="true">true</option> </select> <br/> <br/> Single Property: <pre id="outputSingle">{}</pre><br/> Multiple Properties: <pre id="outputMultiple">{}</pre>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM