【问题标题】:Add elements inside Array conditionally in JavaScript在 JavaScript 中有条件地在 Array 中添加元素
【发布时间】:2021-11-18 06:15:45
【问题描述】:

当我尝试使用扩展运算符有条件地合并两个对象时,它在条件为 truefalse 时有效:

let condition = false;
let obj1 = { key1: 'value1'}
let obj2 = {
  key2: 'value2',
  ...(condition && obj1),
};

// obj2 = {key2: 'value2'};

当我尝试对数组使用相同的逻辑时,它仅在条件为true 时才有效:

let condition = true;
let arr1 = ['value1'];
let arr2 = ['value2', ...(condition && arr1)];

// arr2 = ['value2', 'value1']

如果条件为false,则抛出错误:

let condition = false;
let arr1 = ['value1'];
let arr2 = ['value2', ...(condition && arr1)];

// Error

为什么ArrayObject 的行为不同?

【问题讨论】:

  • 未清除。你想在这里实现什么?你能把你的(condition && arr)也贴上吗?
  • 仅供参考,{ ...null }{ ...undefined } 也不会抛出错误。所以,如果我们不确定一个对象是否有价值,我们也可以放弃这个检查
  • FWIW 如果你想传播布尔值,你可以做类似Boolean.prototype[Symbol.iterator] = function* () {} 的事情(显然不要在生产代码中这样做,它只是一个古董)
  • 是你真正想要达到的目标condition ? [...arr1, ...arr2] : arr1 还是只是关于语言如何工作的问题?
  • @JollyJoker 这只是关于语言如何工作的问题。谢谢

标签: javascript ecmascript-6


【解决方案1】:

当你展开成一个数组时,你调用了对象的Symbol.iterator方法。 && 计算为第一个假值(或最后一个真值,如果所有值都是真值),所以

let arr2 = ['value2', ...(condition && arr)];

结果

let arr2 = ['value2', ...(false)];

但是false 没有Symbol.iterator 方法。

您可以改用条件运算符,如果条件为假,则展开一个空数组:

let condition = false;
let arr1 = ['value1'];
let arr2 = ['value2', ...(condition ? arr1 : [])];
console.log(arr2);

(这是因为空数组确实Symbol.iterator方法)

对象传播完全不同:它将自己的可枚举属性从提供的对象复制到新对象。 false 没有任何自己的可枚举属性,因此不会复制任何内容。

【讨论】:

    【解决方案2】:

    false 不可传播。

    您需要一个可扩展的对象(实现Symbol.iterator 的对象),如果已扩展,它不会返回任何内容。

    您可以使用空数组作为默认值。即使arrfalsy,这也有效。

    let condition = false;
    let arr1 = ['value1'];
    let arr2 = ['value2', ...(condition && arr || [])];
    
    console.log(arr2);

    【讨论】:

    • 将添加括号以使其更清晰((condition && arr) || [])
    • 这确实可以使用?: 运算符而不是链式||
    • @deceze,这真的取决于用例。
    • 我认为 this 是一个用例,?: 更合适。 ;)
    【解决方案3】:

    这是对象字面量和数组字面量的扩展语法之间的规范差异。

    MDN 简要提及它here -- 我强调:

    传播语法(除了传播属性的情况)只能应用于可迭代对象

    区别来自于 EcmaScript 2018 规范:

    • 关于对象传播语法,见12.2.6.8 Runtime Semantics: PropertyDefinitionEvaluation:

      • 它调用CopyDataProperties(object, fromValue, excludedNames),其中 fromValue 被包装到带有ToObject 的对象中,因此变得可迭代,即使 fromValue 是像@987654326 这样的原始值@。因此{...false}有效 EcmaScript。
    • 关于数组展开语法,见12.2.5.2 Runtime Semantics: ArrayAccumulation

      • 它只调用GetValue(spreadRef),它不执行上述包装。因此,随后对GetIterator 的调用将触发原始值的错误,因为它不可迭代。因此[...false]无效 EcmaScript。

    【讨论】:

      【解决方案4】:

      对象示例:

       const lessonMenuItems = [
        ...(true
          ? [
              {
                value: 'post',
              },
            ]
          : []),
        {
          value: 'assign',
        },
      ]
      

      结果:

      lessonMenuItems = [
        {
          value: 'post',
        },
        {
          value: 'assign',
        },
      ]
      

      【讨论】:

        【解决方案5】:

        您可以使用 ternary operator (? :) 并将空数组作为 false

        let condition = false;
        let arr1 = ['value1'];
        let arr2 = ['value2', ...(condition ? arr1 : [])];
        console.log(arr2);

        【讨论】:

          猜你喜欢
          • 2021-06-30
          • 2012-10-09
          • 2012-11-07
          • 1970-01-01
          • 2020-01-27
          • 2015-04-05
          • 1970-01-01
          • 2020-07-30
          相关资源
          最近更新 更多