找出JavaScript数组是否包含值的最简洁有效的方法是什么?

这是我知道的唯一方法:

function contains(a, obj) {
    for (var i = 0; i < a.length; i++) {
        if (a[i] === obj) {
            return true;
        }
    }
    return false;
}

有没有更好、更简洁的方法来实现这一点?

这与堆栈溢出问题密切相关。在JavaScript数组中查找项目的最佳方法是什么?它解决了使用indexOf查找数组中的对象的问题。


当前回答

或此解决方案:

Array.prototype.includes = function (object) {
  return !!+~this.indexOf(object);
};

其他回答

2019年更新:这个答案来自2008年(11岁!),与现代JS用法无关。承诺的性能改进基于当时浏览器中的基准测试。它可能与现代JS执行上下文无关。如果您需要一个简单的解决方案,请寻找其他答案。如果您需要最佳的性能,请在相关的执行环境中进行基准测试。

正如其他人所说,通过数组迭代可能是最好的方法,但事实证明,递减while循环是JavaScript中迭代最快的方法。因此,您可能需要按如下方式重写代码:

function contains(a, obj) {
    var i = a.length;
    while (i--) {
       if (a[i] === obj) {
           return true;
       }
    }
    return false;
}

当然,您还可以扩展Array原型:

Array.prototype.contains = function(obj) {
    var i = this.length;
    while (i--) {
        if (this[i] === obj) {
            return true;
        }
    }
    return false;
}

现在,您可以简单地使用以下命令:

alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false

这绝不是最好的,但我只是在发挥创意,加入到曲目中。

不要使用此

Object.defineProperty(Array.prototype,“exists”{值:函数(元素,索引){var索引=索引||0返回索引==this.length-1:this[index]==元素?索引:this.exists(元素,++索引)}})//输出1console.log(['one','two'].exists('two'));//输出-1console.log(['one','two'].existes('tree'));console.log(['one','two','three','four'].exists('fur'));

ECMAScript 6有一个很好的查找建议。

find方法对每个元素执行一次回调函数出现在数组中,直到找到回调返回true的数组价值如果找到这样的元素,find将立即返回值该元素。否则,find返回undefined。回调是仅对已赋值的数组索引调用;它不会为已删除或从未删除的索引调用已分配值。

这是MDN文档。

查找功能是这样工作的。

function isPrime(element, index, array) {
    var start = 2;
    while (start <= Math.sqrt(element)) {
        if (element % start++ < 1) return false;
    }
    return (element > 1);
}

console.log( [4, 6, 8, 12].find(isPrime) ); // Undefined, not found
console.log( [4, 5, 8, 12].find(isPrime) ); // 5

通过定义函数,可以在ECMAScript 5及以下版本中使用此函数。

if (!Array.prototype.find) {
  Object.defineProperty(Array.prototype, 'find', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(predicate) {
      if (this == null) {
        throw new TypeError('Array.prototype.find called on null or undefined');
      }
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }
      var list = Object(this);
      var length = list.length >>> 0;
      var thisArg = arguments[1];
      var value;

      for (var i = 0; i < length; i++) {
        if (i in list) {
          value = list[i];
          if (predicate.call(thisArg, value, i, list)) {
            return value;
          }
        }
      }
      return undefined;
    }
  });
}

适用于所有现代浏览器的解决方案:

function contains(arr, obj) {
  const stringifiedObj = JSON.stringify(obj); // Cache our object to not call `JSON.stringify` on every iteration
  return arr.some(item => JSON.stringify(item) === stringifiedObj);
}

用法:

contains([{a: 1}, {a: 2}], {a: 1}); // true

IE6+解决方案:

function contains(arr, obj) {
  var stringifiedObj = JSON.stringify(obj)
  return arr.some(function (item) {
    return JSON.stringify(item) === stringifiedObj;
  });
}

// .some polyfill, not needed for IE9+
if (!('some' in Array.prototype)) {
  Array.prototype.some = function (tester, that /*opt*/) {
    for (var i = 0, n = this.length; i < n; i++) {
      if (i in this && tester.call(that, this[i], i, this)) return true;
    } return false;
  };
}

用法:

contains([{a: 1}, {a: 2}], {a: 1}); // true

为什么使用JSON.stringify?

Array.indexOf和Array.includes(以及这里的大多数答案)只通过引用而不是通过值进行比较。

[{a: 1}, {a: 2}].includes({a: 1});
// false, because {a: 1} is a new object

奖金

未经优化的ES6单缸套:

[{a: 1}, {a: 2}].some(item => JSON.stringify(item) === JSON.stringify({a: 1));
// true

注:如果键的顺序相同,则按值比较对象的效果会更好,因此为了安全起见,您可以首先使用以下包对键进行排序:https://www.npmjs.com/package/sort-keys


使用性能优化更新了contains函数。谢谢你指出这一点。

我们使用以下代码段(用于对象、数组和字符串):

/*
 * @function
 * @name Object.prototype.inArray
 * @description Extend Object prototype within inArray function
 *
 * @param {mix}    needle       - Search-able needle
 * @param {bool}   searchInKey  - Search needle in keys?
 *
 */
Object.defineProperty(Object.prototype, 'inArray',{
    value: function(needle, searchInKey){

        var object = this;

        if( Object.prototype.toString.call(needle) === '[object Object]' || 
            Object.prototype.toString.call(needle) === '[object Array]'){
            needle = JSON.stringify(needle);
        }

        return Object.keys(object).some(function(key){

            var value = object[key];

            if( Object.prototype.toString.call(value) === '[object Object]' || 
                Object.prototype.toString.call(value) === '[object Array]'){
                value = JSON.stringify(value);
            }

            if(searchInKey){
                if(value === needle || key === needle){
                return true;
                }
            }else{
                if(value === needle){
                    return true;
                }
            }
        });
    },
    writable: true,
    configurable: true,
    enumerable: false
});

用法:

var a = {one: "first", two: "second", foo: {three: "third"}};
a.inArray("first");          //true
a.inArray("foo");            //false
a.inArray("foo", true);      //true - search by keys
a.inArray({three: "third"}); //true

var b = ["one", "two", "three", "four", {foo: 'val'}];
b.inArray("one");         //true
b.inArray('foo');         //false
b.inArray({foo: 'val'})   //true
b.inArray("{foo: 'val'}") //false

var c = "String";
c.inArray("S");        //true
c.inArray("s");        //false
c.inArray("2", true);  //true
c.inArray("20", true); //false