Определите, есть ли строка в списке в JavaScript - PullRequest
213 голосов
/ 12 марта 2010

В SQL мы можем видеть, есть ли строка в списке следующим образом:

Column IN ('a', 'b', 'c')

Какой хороший способ сделать это в JavaScript? Это так неуклюже, чтобы сделать это:

if (expression1 || expression2 || str === 'a' || str === 'b' || str === 'c') {
   // do something
}

И я не уверен насчет производительности или ясности этого:

if (expression1 || expression2 || {a:1, b:1, c:1}[str]) {
   // do something
}

Или можно использовать функцию переключения:

var str = 'a',
   flag = false;

switch (str) {
   case 'a':
   case 'b':
   case 'c':
      flag = true;
   default:
}

if (expression1 || expression2 || flag) {
   // do something
}

Но это ужасный беспорядок. Есть идеи?

В этом случае мне нужно использовать Internet Explorer 7, так как он предназначен для корпоративной интрасети. Так что ['a', 'b', 'c'].indexOf(str) !== -1 не будет работать изначально без некоторого синтаксического сахара.

Ответы [ 15 ]

242 голосов
/ 12 марта 2010

Вы можете позвонить indexOf:

if (['a', 'b', 'c'].indexOf(str) >= 0) {
    //do something
}
139 голосов
/ 31 марта 2010

EcmaScript 6

Если вы используете ES6, вы можете создать массив элементов и использовать includes:

['a', 'b', 'c'].includes('b')

Это имеет некоторые неотъемлемые преимущества по сравнению с indexOf, поскольку оно может правильно проверять наличие NaN в списке и может сопоставлять отсутствующие элементы массива, такие как средний, в [1, , 2] с undefined. includes также работает на массивах с типом JavaScript , таких как Uint8Array.

без массива

Вы можете добавить новое свойство isInList в строки следующим образом:

if (!String.prototype.isInList) {
   String.prototype.isInList = function() {
      let value = this.valueOf();
      for (let i = 0, l = arguments.length; i < l; i += 1) {
         if (arguments[i] === value) return true;
      }
      return false;
   }
}

Тогда используйте это так:

'fox'.isInList('weasel', 'fox', 'stoat') // true
'fox'.isInList('weasel', 'stoat') // false

Вы можете сделать то же самое для Number.prototype.

Array.indexOf

Если вы используете современный браузер, indexOf всегда работает. Однако для IE8 и более ранних версий вам понадобится полифилл.

Если indexOf возвращает -1, элемент отсутствует в списке. Однако помните, что этот метод не будет правильно проверять NaN, и хотя он может соответствовать явному undefined, он не может сопоставить отсутствующий элемент с undefined, как в массиве [1, , 2].

Polyfill для indexOf в Internet Explorer 8 и более ранних версиях или в любом другом браузере без него

Вы всегда можете использовать совместимый со стандартами пользовательский полифилл , чтобы сделать это в старых браузерах.

В этой ситуации, когда мне нужно было найти решение для Internet Explorer 7, я «свернул свою» более простую версию функции indexOf(), которая не соответствует стандартам:

if (!Array.prototype.indexOf) {
   Array.prototype.indexOf = function(item) {
      var i = this.length;
      while (i--) {
         if (this[i] === item) return i;
      }
      return -1;
   }
}

Однако я не думаю, что изменение Array.prototype - лучший ответ в долгосрочной перспективе. Изменение прототипов Object и Array в JavaScript может привести к серьезным ошибкам. Вы должны решить, насколько это безопасно в вашей среде. Прежде всего следует отметить, что повторение массива (когда Array.prototype имеет добавленные свойства) с for ... in вернет новое имя функции в качестве одного из ключей:

Array.prototype.blah = function() { console.log('blah'); };
let arr = [1, 2, 3];
for (let x in arr) { console.log(x); }
// Result:
0
1
2
blah // Extra member iterated over!

Ваш код может работать сейчас, но в тот момент, когда кто-то в будущем добавит стороннюю библиотеку JavaScript или плагин, который не ревностно защищает от унаследованных ключей, все может сломаться.

Старый способ избежать этой поломки - во время перечисления проверять каждое значение, чтобы увидеть, действительно ли объект имеет его как не наследуемое свойство с if (arr.hasOwnProperty(x)) и только тогда работает с этим x.

Новый способ ES6 избежать этой не ключевой проблемы - использовать of вместо in, for (let x of arr). Однако, если вы не можете гарантировать, что весь ваш код и сторонние библиотеки строго придерживаются этого метода, тогда для целей этого вопроса вы, вероятно, просто захотите использовать includes, как указано выше.

50 голосов
/ 12 марта 2010

В большинстве ответов предлагается метод Array.prototype.indexOf, единственная проблема в том, что он не будет работать на любой версии IE до IE9.

В качестве альтернативы я оставляю вам еще две опции, которые будут работать во всех браузерах:

if (/Foo|Bar|Baz/.test(str)) {
  // ...
}


if (str.match("Foo|Bar|Baz")) {
  // ...
}
25 голосов
/ 12 марта 2010

Массивы имеют метод indexOf, который можно использовать для поиска строк:

js> a = ['foo', 'bar', 'baz']
foo,bar,baz
js> a.indexOf('bar')
1
js> a.indexOf('quux')
-1
11 голосов
/ 12 марта 2010

Я использовал трюк

>>> ("something" in {"a string":"", "somthing":"", "another string":""})
false
>>> ("something" in {"a string":"", "something":"", "another string":""})
true

Вы могли бы сделать что-то вроде

>>> a = ["a string", "something", "another string"];
>>> b = {};
>>> for(var i=0; i<a.length;i++){b[a[i]]="";} /* Transform the array in a dict */
>>> ("something" in b)
true
8 голосов
/ 14 февраля 2014

Вот мой:

String.prototype.inList=function(list){
    return (Array.apply(null, arguments).indexOf(this.toString()) != -1)
}

var x = 'abc';
if (x.inList('aaa','bbb','abc'))
    console.log('yes');
else
    console.log('no');

Это быстрее, если вы в порядке с передачей массива:

String.prototype.inList=function(list){
    return (list.indexOf(this.toString()) != -1)
}

var x = 'abc';
if (x.inList(['aaa','bbb','abc']))
    console.log('yes')

Вот jsperf: http://jsperf.com/bmcgin-inlsit

6 голосов
/ 06 марта 2015

RegExp универсально, но я понимаю, что вы работаете с массивами. Итак, проверьте этот подход. Я использую его, и он очень эффективен и быстро работает!

var str = 'some string with a';
var list = ['a', 'b', 'c'];
var rx = new RegExp(list.join('|'));

rx.test(str);

Вы также можете применить некоторые модификации, т.е.

One-лайнер

new RegExp(list.join('|')).test(str);

без учета регистра

var rx = new RegExp(list.join('|').concat('/i'));


и многие другие!

5 голосов
/ 12 марта 2010

Похоже, вам нужно использовать функцию in_array.

jQuery -> inArray

Прототип -> Array.indexOf

Или посмотрите эти примеры, если вы не используете jQuery или Prototype:

Стилистическое примечание: переменные, названные thisthing thatthing, должны быть названы так, чтобы рассказать вам о том, что они содержат (существительное).

5 голосов
/ 12 марта 2010

В дополнение к indexOf (что предложили другие авторы), использование прототипа Enumerable.include () может сделать это более аккуратным и лаконичным:

var list = ['a', 'b', 'c'];
if (list.include(str)) {
  // do stuff
}
2 голосов
/ 26 февраля 2019

Использование indexOf (он не работает с IE8).

if (['apple', 'cherry', 'orange', 'banana'].indexOf(value) >= 0) {
    // found
}

Для поддержки IE8 вы можете реализовать Mozilla indexOf.

if (!Array.prototype.indexOf) {
    // indexOf polyfill code here
}

Регулярные выражения через String.prototype.match (docs).

if (fruit.match(/^(banana|lemon|mango|pineapple)$/)) {

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...