【问题标题】:Check if array includes a value检查数组是否包含值
【发布时间】:2019-08-10 19:46:57
【问题描述】:

我有一个对象数组,我需要防止将重复的对象添加到数组中。我尝试了以下代码来检查重复项:

const array = [{ name: 'John' }];

const newName = {
  name: 'John'
};
console.log(array);
console.log(newName);

if (array.includes(newName)) {
  console.log(newName.name + ' exists');
} else {
  console.log('name does not exist');
}

控制台日志告诉对象NewName 与array[0] 完全相同。然而,

if(array.includes(newName))

返回 false。

我做错了什么?我也尝试了这篇文章中的解决方案,但没有运气:

How do I check if an array includes an object in JavaScript?

【问题讨论】:

标签: javascript arrays object


【解决方案1】:

简单地说,你可以使用array.some from Array.prototype.some() documentation.

在您自己的示例中,您可以对您的程序进行一些调整:

const array = [{ name: "John" }];

  const newName = {
    name: "John"
  };
  console.log(array);
  console.log(newName);

  if (array.some(object => object.name === newName.name)) {
    console.log(newName.name + " exists");
  } else {
    console.log("name does not exist");
  }

【讨论】:

    【解决方案2】:

    如果name是对象的标识,可以在数组上使用some函数:

    const array = [{ name: 'John' }];    
    const newName = { name: 'John' };
    
    if (array.some(({name}) => name === newName.name)) {
      console.log(newName.name + ' exists');
    } else {
      console.log('name does not exist');
    }

    或者你可以检查属性的数量是否相同,然后每个属性都有:

    const array = [{ name: 'John', age: 33 }, { name: 'John', age: 45 }];    
    const newName = { age: 33, name: 'John' };
    
    if (array.some(x => Object.keys(x).length === Object.keys(newName).length && Object.keys(x).every(p => x[p] === newName[p]))) {
      console.log(newName.name + ' exists');
    } else {
      console.log('name does not exist');
    }

    【讨论】:

      【解决方案3】:

      这是因为您试图比较两个不同的对象实例,它们永远不会相等。

      但是,如果您通过 JSON.stringify 将对象转换为原始字符串,则可以使用 Array.includes 进行深度比较。正如 ttulka 所指出的,这仅在要搜索的对象与要在数组中查找的对象具有相同顺序 的属性时才有效。

      const array = [{ name: 'John', age: 33 }];
      const newName = {
        name: 'John',
        age: 33
      };
      if (array.map(obj => JSON.stringify(obj)).includes(JSON.stringify(newName))) {
        console.log(newName.name + ' exists');
      } else {
        console.log('name does not exist');
      }

      如果您查看 MDN 中的 Array#includes polyfill,您会看到使用 === 严格相等运算符进行比较:

      function sameValueZero(x, y) {
         return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
      }
      
      // 7. Repeat, while k < len
      while (k < len) {
        // a. Let elementK be the result of ? Get(O, ! ToString(k)).
        // b. If SameValueZero(valueToFind, elementK) is true, return true.
        if (sameValueZero(o[k], valueToFind)) {
            return true;
        }
        // c. Increase k by 1. 
        k++;
      }
      

      因此,当您使用 === 比较两个不同的对象字面量时,它们将不相等:

      console.log({name :"John"} === {name :"John"});

      但另一方面,如果将原始字符串与=== 进行比较,它们是相等的:

      console.log('{name:"John"}' === '{name:"John"}');

      但对于 String 对象却不是这样:

      console.log(new String('{name:"John"}') === new String('{name:"John"}'));

      【讨论】:

      • JSON.stringify 不适用于 const array = [{ name: 'John', age: 33 }]; const newName = { age: 33, name: 'John'};,即使对象实际上是相同的。
      • 不,你没有……改变属性的顺序……JSON.stringify({ age: 33, name: 'John' }) !== JSON.stringify({ name: 'John', age: 33 })
      • @ttulka 是的,如果您更改顺序,JSON.stringify 的输出字符串将不同,因此它们将不相等。
      • @ttulka 我会在我的回答中更新这个观察结果,感谢您指出这一点!
      【解决方案4】:

      const array = [{
        name: 'John'
      }];
      
      const newName = {
        name: 'John'
      };
      
      let resultArr = array.filter((item) => {
        return item.name === newName.name
      })
      
      let elementPresentMsg;
      
      if (resultArr.length > 0) {
        elementPresentMsg = newName.name + ' exists';
      } else {
        elementPresentMsg = 'name does not exist'
      }
      
      document.getElementById('msg').innerHTML = elementPresentMsg;
      <html>
      
      <body>
      
        <p id="msg"></p>
      
      </body>
      
      </html>

      如果要从数组中查找名称或任何其他值,如果对象的属性与对象数组中的属性相同,则以下内容应该会有所帮助:

      const array = [{ name: 'John' }];
      
      const newName = {
        name: 'John'
      };
      
      let resultArr = array.filter((item) => {
          return item.name === newName.name
      })
      
      if (resultArr.length > 0) {
        alert(newName.name + ' exists'); //any way to print result instead of alert
      } else {
        alert('name does not exist'); //any way to print result instead of alert
      }
      

      【讨论】:

        【解决方案5】:

        那是因为array[0] 不等于newName。在 Javascript 中,它们指向不同的元素。你可以试试console.log(array[0] == newName),你会得到false
        如果要查找重复项,可以这样尝试:

        if (JSON.stringify(array).indexOf(JSON.stringify(newName)) != -1) {
          console.log('exist')
        }
        else {
          console.log('not exist')
        }
        

        【讨论】:

        • 这通常不起作用,因为JSON.stringify({ age: 33, name: 'John' }) !== JSON.stringify({ name: 'John', age: 33 })
        • @ttulka 我以为输入顺序是固定的,这是我的错。
        【解决方案6】:

        使用它:

        var newName = {
         name: 'John'
        };
        console.log(array);
        console.log(newName.name);
        var found = array.some(obj => obj.name === newName.name);
        
        if (found) {
         console.log(newName.name + ' exists');
        } else {
         console.log('name does not exist');
        }
        

        【讨论】:

          【解决方案7】:

          您缺少的是includes 在您在对象上使用它时检查身份newName 与数组中的对象具有相同的属性,但它不是同一个对象,只要两个名为 John 的人是同一个人。举个更明显的例子,运行{} == {},你会得到false

          要检查数组是否包含同名对象,可以使用some 并传递给它一个函数来比较对象,例如

          array.some(e => e.name == newName.name)
          

          【讨论】:

            猜你喜欢
            • 2015-01-01
            • 2021-07-15
            • 1970-01-01
            • 2016-02-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-06-06
            • 1970-01-01
            相关资源
            最近更新 更多