确定字符串是否在JavaScript列表中


262

在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用于公司Intranet页面。因此,['a', 'b', 'c'].indexOf(str) !== -1没有一些语法糖就无法在本地运行。


1
您能解释一下“字符串在列表中”和“数组包含一个对象”之间的区别是什么吗?
米哈尔Perłakowski

2
@Gothdo因为列表并不总是数组,而字符串也不是对象?怎么会更清楚?
ErikE

@ErikE,如果是您在NOTE中提到的情况,则应关闭此问题,不应再有任何赏金/答案。已经发布的答案足以使任何人获得帮助。
Vikasdeep Singh

@VicJordan也许您想删除您的评论,因为它不再适用。
ErikE

Answers:


279

您可以致电indexOf

if (['a', 'b', 'c'].indexOf(str) >= 0) {
    //do something
}

15
唯一的问题Array.prototype.indexOf是它无法在IE上运行,可悲的是,即使IE8也缺少此方法。
CMS 2010年



8
@ImJasonH:该页面上的代码确实是不好的恕我直言,例如,Array.indexOf在覆盖之前检查是否存在,Array.prototype.indexOf不是同一回事。我会建议由Mozilla可以在这里所作的落实:developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/...
CMS

1
听@ CMS,@ Emtucifor,Mozilla的实现要好得多。
杰森·霍尔

230

EcmaScript 6

如果您使用的是ES6,则可以构造一系列项目,并使用includes

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

这样做有一些内在的好处,indexOf因为它可以正确测试NaN列表中是否存在,并且可以将缺少的数组元素(例如中间的元素)匹配[1, , 2]到中undefinedincludes也适用于JavaScript类型的数组,例如Uint8Array

如果您担心浏览器支持(例如IE或Edge),可以在CanIUse.Com上进行检查Array.includes,并且如果要定位缺少的浏览器或浏览器版本,includes建议使用polyfill.io进行polyfilling。

没有数组

您可以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和更早版本,您将需要一个polyfill。

如果indexOf返回-1,则该项目不在列表中。不过请注意,此方法将无法正确检查NaN,尽管它可以匹配显式undefined,但不能将缺少的元素undefined与array中的匹配[1, , 2]

适用于IE indexOfincludesIE中的Polyfill ,或任何其他缺少支持的浏览器/版本

如果您不想使用上述提及的polyfill.io之类的服务,则始终可以在自己的源代码中包括符合标准的自定义polyfill。例如,Mozilla Developer Network有一个用于indexOf

在这种情况下,我必须为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从长远来看,我认为修改不是最好的答案。用JavaScript 修改ObjectArray原型可能会导致严重的错误。您需要确定这样做在您自己的环境中是否安全。首先要注意的是,使用进行数组迭代(当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的,而不是infor (let x of arr)。但是,除非您可以保证所有代码和第三方库都严格遵守此方法,否则出于此问题的目的,您可能只想includes如上所述使用。


2
这里的另一个很好的填充工具用于indexOf由MDN提供。它基本上做同样的事情,但是有几个短路电路,以便于评估。
KyleMit 2014年

1
Downvoter:请发表评论。这是什么问题?此功能不符合标准,也没有尝试这样做。
ErikE 2015年

:您应该使用已经测试通过类似链接@KyleMit提到的填充工具的东西developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
lmiguelmh

@lmiguelmh我自己从Mozilla文档本身发布了链接的“ polyfill”呢?无论如何,此功能是如此简单,以至于我真的不太担心测试。而且,任何人都不应采用“已经测试过”的功能,而应该自己测试使用的功能。因此,您的评论有误。您确定我的功能存在特定缺陷吗?
ErikE

@ErikE,您说对了,此功能已失效,任何使用您答案的人都应该知道。我没有看到您的链接,因为我一直在寻找“答案”
lmiguelmh

53

大多数答案都建议使用该Array.prototype.indexOf方法,唯一的问题是,它在IE9之前的任何 IE版本上均不起作用。

作为替代方案,我为您提供了两个可以在所有浏览器上使用的选项:

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


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

嗯,谢谢您提到CMS。碰巧这是针对公司Intranet的,他们使用...猜猜是什么... IE。由于正则表达式方法使我意志坚定,所以我要么必须做一个循环的函数,要么要使用我在帖子(第三个代码块)中建议的对象方法。
ErikE 2010年

13
这将匹配"HiFooThere"-我会选择/^(?:Foo|Bar|Baz)$/(字符串开头,非捕获组,字符串结尾)。
TrueWill

indexOf根据MDN,IE 9和更高版本现在支持。
krock 2015年

28

数组具有indexOf可用于搜索字符串的方法:

js> a = ['foo', 'bar', 'baz']
foo,bar,baz
js> a.indexOf('bar')
1
js> a.indexOf('quux')
-1

3
这将在较旧的浏览器上失败。
epascarello 2010年

糟糕...提到这在IE中不起作用,那就太好了。:)
ErikE

2
@epascarello:不仅在旧版浏览器中,它在任何 IE 上将失败,即使在IE8中也是如此:(
CMS 2010年

12

我使用的一个技巧是

>>> ("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

航海家,正在使用“更快”,“更慢” /“更好” /“更差”的“输入”,而不是像问题中显示的第三个代码块那样尝试取消引用该项目?另外,如果您要遍历事物,我想您也可以检查一下元素是否在数组中……只需将循环包装在函数中即可。值得考虑的var i=a.length;while (i--) {/*use a[i]*/}是最快的循环方法(如果可以接受反向顺序)。
ErikE 2010年

@Emtucifor:它实际上取决于您在做什么,我想它在不同的JavaScript引擎上可能会有所不同。如果您的数据在任何时候都需要使用字典,那么最好以这种方式创建它。我认为这样做会更快,因为一旦创建dict对象,引擎上的实现细节(对象使用哈希表)就可以了
EstebanKüber2010年

在JavaScript中,它不称为dict,它称为object
所罗门·乌科

8

这是我的:

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


坦白说,传递数组的方法可能会更有用,并且应该在Array的原型上:可能类似Array.prototype.contains
所罗门·乌科

6

RegExp是通用的,但我了解您正在使用数组。因此,请查看此方法。我曾经使用过它,它非常有效而且速度很快!

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

rx.test(str);

您还可以应用一些修改,即:

一线

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

不区分大小写

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


还有很多!


使用正则表达式需要避免一堆特殊字符。这也不太清楚。我认为这不是一个好的解决方案。
ErikE 2015年

@ErikE我了解您的保留,因此我更新了答案,添加了另一个不使用RegExp的代码,它与IE具有追溯兼容性,非常习惯和快速。
sospedra

您的其他代码与我的答案几乎是重复的,在您决定发布Regex解决方案之前,我提供了5年的答案。感谢您的参与,与此同时,我认为回滚您之前的答案是最好的。
ErikE

@ErikE是的,您是对的,我不习惯检查问题的答案。我同意这确实很相似。
sospedra

6

使用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)$/)) {

}

1
您是否注意到您确实在复制页面上的其他答案?这不会增加任何价值。
ErikE

5

看起来您需要使用in_array函数。

jQuery-> inArray

原型-> Array.indexOf

或者,如果您不使用jQuery或Prototype,请参见以下示例:

风格注释:应命名为thisthing thatthing的变量,以告诉您有关其所包含内容的信息(名词)。


哦,它们不是变量,而是作为表达式的随机占位符……只是我计划如何使用脚本的一个示例。
ErikE 2010年


2

感谢您提出的问题,以及使用Array.indexOf方法的解决方案。

我使用此解决方案中的代码创建了一个inList()函数,该函数将使IMO的编写更加简单,阅读更加清晰:

function inList(psString, psList) 
{
    var laList = psList.split(',');

    var i = laList.length;
    while (i--) {
        if (laList[i] === psString) return true;
    }
    return false;
}

用法:

if (inList('Houston', 'LA,New York,Houston') {
  // THEN do something when your string is in the list
}

1
Javascript数组文字非常简单,我不明白为什么您会在可能的情况下拆分'Houston'.inList(['LA', 'New York', 'Houston'])。也许if (!String.prototype.inList) {String.prototype.inList = function(arr) {return arr.indexOf(this) >= 0};}或使用您的while方法。
ErikE 2011年

0

我很惊讶,没有人提到一个简单的函数,它需要一个字符串和一个列表。

function in_list(needle, hay)
{
    var i, len;

    for (i = 0, len = hay.length; i < len; i++)
    {
        if (hay[i] == needle) { return true; }
    }

    return false;
}

var alist = ["test"];

console.log(in_list("test", alist));

吉姆(Sam)确实按照您的建议做了,萨姆(Sam),11年8月27日,下午1:29。实际上,我选择的答案几乎是同一回事,只是向字符串提供此内容而不是参数。
ErikE 2012年

@ErikE对不起,Jims的回答对我来说似乎很奇怪。您接受的答案将返回int,因为有些人可能会遇到此问题以寻求bool回报。认为这可能会帮助一些人。
塞缪尔·帕金森

0

我的解决方案产生这样的语法:

// Checking to see if var 'column' is in array ['a', 'b', 'c']

if (column.isAmong(['a', 'b', 'c']) {
  // Do something
}

我通过扩展基本的Object原型来实现这一点,如下所示:

Object.prototype.isAmong = function (MyArray){
   for (var a=0; a<MyArray.length; a++) {
      if (this === MyArray[a]) { 
          return true;
      }
   }
   return false;
}

我们可以选择将方法命名为isInArray(但可能不会命名为inArray)或简称为isIn。

优点:简单,直接和可自我记录。


扩展对象可能会遇到麻烦。bolinfest.com/javascript/inheritance.php下的“ Google Maps团队很难学到这一点”,并且与浏览器实现或其他用户代码不兼容。我仍然认为ErikE的答案是最好的,因为遍历数组比创建哈希图后在哈希图中查找键要慢:myValues[key];其中myValues是对象,键是任何字符串或数字。
HMR

-1

SLaks答案的简化版本也可以使用:

if ('abcdefghij'.indexOf(str) >= 0) {
    // Do something
}

....因为字符串本身就是数组。:)

如果需要,请按照我之前的描述为Internet Explorer实现indexof函数。


1
这仅适用于单字母字符串,这不是故意的。
ErikE
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.