a

Câu hỏi Làm thế nào để kiểm tra xem một mảng có chứa một đối tượng trong JavaScript không?


Cách ngắn gọn và hiệu quả nhất để tìm hiểu xem một mảng JavaScript có chứa một đối tượng không?

Đây là cách duy nhất tôi biết để làm điều đó:

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

Có cách nào tốt hơn và súc tích hơn để thực hiện việc này không?

Điều này liên quan chặt chẽ đến câu hỏi Stack Overflow Cách tốt nhất để tìm một mục trong một mảng JavaScript? địa chỉ tìm kiếm các đối tượng trong một mảng bằng cách sử dụng indexOf.


3226
2017-10-25 22:14


gốc


vừa được thử nghiệm: cách của bạn thực sự là nhanh nhất trên các trình duyệt: jsperf.com/find-element-in-obj-vs-array/2 (ngoài việc tiết kiệm a.length trong một biến) trong khi sử dụng indexOf (như trong $ .inArray) là chậm hơn nhiều - Jörn Berkefeld
nhiều người đã trả lời rằng Array # indexOf là lựa chọn tốt nhất của bạn ở đây. Nhưng nếu bạn muốn một cái gì đó có thể được đúc một cách chính xác để Boolean, sử dụng này: ~[1,2,3].indexOf(4) sẽ trả về 0 sẽ đánh giá là sai, trong khi ~[1,2,3].indexOf(3) sẽ trả về -3 sẽ đánh giá là đúng. - lordvlad
~ không phải là những gì bạn muốn sử dụng để chuyển đổi sang boolean, cho điều bạn cần !. Nhưng trong trường hợp này bạn muốn kiểm tra sự bình đẳng với -1, s o hàm có thể kết thúcreturn [1,2,3].indexOf(3) === -1;  ~ không phải là nhị phân, nó sẽ đảo ngược từng bit của giá trị riêng lẻ. - mcfedr
@Iordvlad [1,2,3].indexOf(4) sẽ thực sự return -1. Như @mcfedr đã chỉ ra, ~ là toán tử bitwise-NOT, xem ES5 11.4.8. Thing là, vì biểu diễn nhị phân của -1 chỉ bao gồm 1, bổ sung là 0, đánh giá là sai. Sự bổ sung của bất kỳ số nào khác sẽ là số không, do đó đúng. Vì thế, ~ hoạt động tốt và thường được sử dụng kết hợp với indexOf. - mknecht
Tiêu đề là gây hiểu nhầm. Đâu là [[1,2],[3,4]].includes([3,4]) ? - mplungjan


Các câu trả lời:


Trình duyệt hiện tại có Array#includes, cái nào chính xác cái đó, được hỗ trợ rộng rãivà có polyfill cho các trình duyệt cũ hơn.

> ['joe', 'jane', 'mary'].includes('jane');
true 

Bạn cũng có thể dùng Array#indexOf, ít trực tiếp hơn nhưng không yêu cầu Polyfills cho trình duyệt cũ.

jQuery cung cấp $.inArray, có chức năng tương đương với Array#indexOf.

underscore.js, một thư viện tiện ích JavaScript, cung cấp _.contains(list, value), bí danh _.include(list, value), cả hai đều sử dụng Chỉ số nội bộ nếu thông qua một mảng JavaScript.

Một số khung công tác khác cung cấp các phương thức tương tự:

Lưu ý rằng một số khung công tác thực hiện điều này như là một hàm, trong khi các khung công tác khác thêm hàm này vào nguyên mẫu mảng.


3650
2017-10-25 23:10



MooTools cũng có Array.contains trả về một boolean, nghe giống như câu hỏi thực sự ở đây. - Ryan Florence
nguyên mẫu cũng có Array.includetrả về boolean - user102008
Nếu bạn đang sử dụng trình duyệt tốt, bạn chỉ có thể sử dụng array.indexOf(object) != -1 - Sam Soffes
Ngoài ra, không sử dụng indexOf một mình như một điều kiện, bởi vì phần tử đầu tiên sẽ trả về 0 và sẽ được đánh giá là bị lỗi - plus-
inArray là tên khủng khiếp cho hàm trả về chỉ mục của phần tử và -1 nếu nó không tồn tại. Tôi mong đợi một boolean được trả lại. - Tim


Cập nhật: Khi @orip đề cập trong nhận xét, điểm chuẩn được liên kết đã được thực hiện trong năm 2008, do đó kết quả có thể không liên quan đến các trình duyệt hiện đại. Tuy nhiên, có thể bạn cần điều này để hỗ trợ các trình duyệt không hiện đại và có thể chúng chưa được cập nhật kể từ đó. Luôn tự kiểm tra.

Như những người khác đã nói, sự lặp lại thông qua mảng có lẽ là cách tốt nhất, nhưng nó Đã được chứng minh rằng giảm while vòng lặp là cách nhanh nhất để lặp lại trong JavaScript. Vì vậy, bạn có thể muốn viết lại mã của mình như sau:

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

Tất nhiên, bạn cũng có thể mở rộng nguyên mẫu Array:

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

Và bây giờ bạn có thể chỉ cần sử dụng như sau:

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

357
2017-10-25 22:49



Nhưng hãy cẩn thận: stackoverflow.com/questions/237104/javascript-array-containsobj/… - MatrixFrog
"Đã được chứng minh" là một từ mạnh mẽ. Các công cụ JS liên tục cải thiện và thời gian thực hiện được đo 3 năm trước là lỗi thời khủng khiếp. - orip
@Damir - Tôi đồng ý. Có lẽ thay đổi mẫu để sử dụng indexOf nếu có, chỉ để mọi người sao chép-dán mã này một cách mù quáng sẽ nhận được hiệu suất tốt nhất mà họ có thể. - orip
@cbmeeks vâng, chăm sóc chắc chắn là cần thiết. Nó có lẽ là một trường hợp làm for (o in array) mà không nên được thực hiện khi lặp qua mảng thường ... - Damir Zekić
Cách tốt nhất để làm điều này là kiểm tra xem [1, 2, 3] .indexOf (1)> -1 - Devin G Rhode


indexOf có thể, nhưng đó là một "phần mở rộng JavaScript cho tiêu chuẩn ECMA-262, vì vậy nó có thể không có mặt trong các triển khai khác của tiêu chuẩn."

Thí dụ:

[1, 2, 3].indexOf(1) => 0
["foo", "bar", "baz"].indexOf("bar") => 1
[1, 2, 3].indexOf(4) => -1

AFAICS Microsoft không phải cung cấp một số loại thay thế cho điều này, nhưng bạn có thể thêm chức năng tương tự vào các mảng trong Internet Explorer (và các trình duyệt khác không hỗ trợ indexOf) nếu bạn muốn, như một tìm kiếm nhanh trên Google cho thấy (ví dụ, cái này).


156
2018-01-01 01:40



trên thực tế, có một ví dụ về việc triển khai phần mở rộng indexOf cho các trình duyệt không hỗ trợ nó trên trang developer.mozilla.org mà bạn đã liên kết đến. - Lloyd Cotten
trên thực tế, nếu bạn thêm indexof vào prototype của Array cho các trình duyệt không hỗ trợ nó (tức là IE7), chúng cũng sẽ cố gắng lặp qua hàm này khi lặp qua các mục trong mảng. bẩn thỉu. - CpILL
IE9 hiện hỗ trợ điều này - Liam
nó có thể áp dụng để kiểm tra đối tượng.? tôi không nghĩ rằng nó hoạt động trong trường hợp của đối tượng - Himesh Aadeshara


Giới thiệu ECMAScript 7 Array.prototype.includes.

Nó có thể được sử dụng như thế này:

[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false

Nó cũng chấp nhận một đối số thứ hai tùy chọn fromIndex:

[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true

không giống indexOf, sử dụng So sánh bình đẳng nghiêm ngặt, includes so sánh việc sử dụng SameValueZero thuật toán bình đẳng. Điều đó có nghĩa là bạn có thể phát hiện nếu một mảng bao gồm NaN:

[1, 2, NaN].includes(NaN); // true

Cũng không giống indexOf, includes không bỏ qua các chỉ mục bị thiếu:

new Array(5).includes(undefined); // true

Hiện tại, nó vẫn là bản nháp nhưng có thể làm đầyđể làm cho nó hoạt động trên tất cả các trình duyệt.


128
2018-03-24 04:59



Không được hỗ trợ cho IE và Microsfot Edge (2015) (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…) - Adriano Resende
Cũng có liên quan, Bảng tương thích ES7 (có vẻ như Chrome hỗ trợ nó ngay bây giờ) - styfle
Đáng chú ý rằng điều này được hỗ trợ trong Node 6+, theo node.green - Ryan
nó có thể áp dụng để kiểm tra đối tượng.? tôi không nghĩ rằng nó hoạt động trong trường hợp của đối tượng - Himesh Aadeshara


b là giá trị và a là mảng. Nó trở lại true hoặc là false:

function(a, b) {
    return a.indexOf(b) != -1
}

96
2017-10-27 00:38



Phần này tôi không hiểu "!! ~". Và tôi nghĩ rằng điều này sẽ không hoạt động trong IE8 vì IE8 không hỗ trợ indexOf () trên đối tượng Array. - svlada
"~" là toán tử có sàn, đảo ngược và trừ 1 từ một số. indexOf trả về -1 nếu nó thất bại, vì vậy "~" biến -1 thành "0". sử dụng "!!" biến số thành boleans (!! 0 === false) - william malo
hiệu suất tương tự như! = - 1 jsperf.com/indexof-check - aelgoa
Chỉ cần một chút ném lên, ngay trong miệng tôi. Mã hoàn toàn không chuyên nghiệp. - Michael Cole
Tôi muốn gọi là thiếu kiến ​​thức về tác động của các toán tử boolean không chuyên nghiệp. Nhưng tôi đồng ý về giá trị của mã có thể đọc được, tôi chắc chắn sẽ bọc nó trong một chức năng được dán nhãn rõ ràng. Và đó chính là điều mà hầu hết các khuôn khổ JS chính làm. - Fx32


Đây là một Tương thích với JavaScript 1.6 thực hiện Array.indexOf:

if (!Array.indexOf)
{
  Array.indexOf = [].indexOf ?
      function (arr, obj, from) { return arr.indexOf(obj, from); }:
      function (arr, obj, from) { // (for IE6)
        var l = arr.length,
            i = from ? parseInt( (1*from) + (from<0 ? l:0), 10) : 0;
        i = i<0 ? 0 : i;
        for (; i<l; i++) {
          if (i in arr  &&  arr[i] === obj) { return i; }
        }
        return -1;
      };
}

65
2017-09-13 17:32



Điều này có vẻ tuyệt vời, nhưng một chút bối rối: * Không phải là các bài kiểm tra trên dòng 1 và 3 tương đương? * Nó sẽ không thể tốt hơn để kiểm tra nguyên mẫu, và thêm hàm vào Array.prototype nếu cần thiết? - Avi Flax
Họ không phải là equvialent. [].indexOf là viết tắt của Array.prototype.indexOf. Chúng tôi lập trình Javascript paranoid phòng thủ tránh mở rộng nguyên mẫu nguyên bản bằng mọi giá. - Már Örlygsson
Không phải [].indexOf tạo một mảng mới và sau đó truy cập indexOf, trong khi Array.prototype.indexOfchỉ truy cập trực tiếp nguyên mẫu? - alex
@alex yes [].indexOf === Array.prototype.indexOf (thử nó trong FireBug), nhưng ngược lại [].indexOf !== Array.indexOf. - Már Örlygsson


Sử dụng:

function isInArray(array, search)
{
    return array.indexOf(search) >= 0;
}

// Usage
if(isInArray(my_array, "my_value"))
{
    //...
}

46
2017-08-27 16:45



x ? true : false thường là thừa. Nó ở đây. - Ry-♦
@minitech Tại sao bạn nói nó là thừa? - Matías Cánepa
array.indexOf(search) >= 0 đã là một boolean. Chỉ return array.indexOf(search) >= 0. - Ry-♦
@minitech cũng cảm ơn! Thực ra tôi không biết rằng một công trình như vậy có thể được trả lại. TIL một cái gì đó mới. - Matías Cánepa
Theo nghĩa đen bất kỳ cấu trúc nào trong javascript đều có thể được trả về - B T


Mở rộng JavaScript Array đối tượng là một ý tưởng thực sự tồi vì bạn giới thiệu các thuộc tính mới (các phương thức tùy chỉnh của bạn) thành for-in các vòng lặp có thể phá vỡ các tập lệnh hiện có. Một vài năm trước, các tác giả của Prototype thư viện đã phải tái thiết kế thư viện của họ để loại bỏ những thứ như thế này.

Nếu bạn không cần phải lo lắng về khả năng tương thích với các JavaScript khác đang chạy trên trang của mình, hãy sử dụng nó, nếu không, tôi khuyên bạn nên giải pháp chức năng tự do khó xử hơn nhưng an toàn hơn.


38
2017-07-18 14:36



Tôi không đồng ý. Các vòng lặp for-in không nên được sử dụng cho các mảng vì lý do chính xác này. Sử dụng các vòng lặp for-in sẽ phá vỡ khi sử dụng một trong các thư viện js phổ biến - Tomas
Điều này có được coi là vá khỉ không? lol Một số người như thế. - cbmeeks


Bạn có thể dùng Array.prototype.some ()

const items = [ {a: '1'}, {a: '2'}, {a: '3'} ]

items.some(item => item.a === '3')  // returns true
items.some(item => item.a === '4')  // returns false

Ngược lại với điều này là việc lặp lại bị hủy bỏ khi phần tử được tìm thấy nên các chu kỳ lặp lại không cần thiết được lưu lại.

Một điều cần lưu ý là some() không có mặt trong tất cả các phiên bản js: (từ trang web)

một số đã được thêm vào tiêu chuẩn ECMA-262 trong ấn bản thứ năm; như vậy nó   có thể không có mặt trong tất cả việc triển khai tiêu chuẩn

Bạn có thể sử dụng nó trong Node.js mà không có bất kỳ vấn đề nào. Nếu bạn cần phải hỗ trợ tất cả các trình duyệt thì có polyfill này (từ cùng một liên kết):

if (!Array.prototype.some)
{
  Array.prototype.some = function(fun /*, thisArg */)
  {
    'use strict';

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== 'function')
      throw new TypeError();

    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++)
    {
      if (i in t && fun.call(thisArg, t[i], i, t))
        return true;
    }

    return false;
  };
}

33
2018-01-07 12:49





Lót:

function contains(arr, x) {
    return arr.filter(function(elem) { return elem == x }).length > 0;
}

21
2017-12-23 15:59



array.filter(e=>e==x).length > 0 tương đương với array.some(e=>e==x) nhưng some hiệu quả hơn - Apolo


Suy nghĩ ra khỏi hộp trong một giây, nếu bạn đang thực hiện cuộc gọi này nhiều lần, nó sẽ hiệu quả hơn rất nhiều khi sử dụng một mảng kết hợp Bản đồ để thực hiện tra cứu bằng hàm băm.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map


21
2018-06-15 01:15