在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
}

或者可以使用switch函数:

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如果没有一些语法糖就不能正常工作。


数组有一个indexOf方法,可以用来搜索字符串:

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

你可以调用indexOf:

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

除了indexOf(这是其他海报的建议),使用原型的Enumerable.include()可以使这更简洁:

var list = ['a', 'b', 'c'];
if (list.includes(str)) {
  // do stuff
}

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

jQuery -> inArray

Prototype -> Array.indexOf

或者,如果你不使用jQuery或Prototype,看看这些例子:

http://phpjs.org/functions/in_array:432 http://www.bitrepository.com/equivalent-of-phps-in_array-function.html http://codingforums.com/showthread.php?t=63796

风格注意:命名为thisthing, thatthing的变量应该告诉你它们包含什么(名词)。


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

作为替代,我给你留下了两个可以在所有浏览器上工作的选项:

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


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

我用过的一个技巧是

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

ES6(2015)和up

如果你使用的是ECMAScript 6(也就是ES2015)或更高版本,最干净的方法是构造一个数组的项目,并使用array .includes:

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

与indexOf相比,这有一些固有的好处,因为它可以正确地测试列表中是否存在NaN,并且可以将缺少的数组元素(如[1,,2]中的中间元素)匹配为undefined。它还将+0和-0视为相等。includes也适用于JavaScript类型数组,如Uint8Array。

如果你担心浏览器的支持(比如IE或Edge),你可以选择Array。在CanIUse.Com上,如果您想要针对缺少include的浏览器或浏览器版本,则需要使用Babel等工具编译到较低的ECMAScript版本,或者在浏览器中包含polyfill脚本,例如在polyfill.io上提供的那些脚本。

更高的性能

注意,不能保证array .includes()的执行时间不随数组中元素的数量而变化:它的性能可以是O(n)。如果你需要更高的性能,并且不会重复构造项目集(但会重复检查项目是否包含一些元素),你应该使用set,因为ES规范要求set(以及Map)的实现是子线性的读取:

规范要求实现的集合“平均而言,提供的访问时间与集合中元素的数量呈次线性关系”。因此,它可以在内部表示为哈希表(具有O(1)查找)、搜索树(具有O(log(N))查找)或任何其他数据结构,只要复杂度优于O(N)。

const interestingItems = new Set(['a', 'b', 'c'])
const isItemInSet = interestingItems.has('b')

请注意,您可以将任何可迭代项传递给Set构造函数(任何支持…of的对象)。你也可以使用array .from(Set)或展开它[…Set]将一个Set转换为数组。

没有数组

不建议这样做,但是你可以为字符串添加一个新的isInList属性,如下所示:

if (!String.prototype.isInList) {
  Object.defineProperty(String.prototype, 'isInList', {
    get: () => function(...args) {
      let value = this.valueOf();
      for (let i = 0, l = args.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做同样的事情。

注意Object.defineProperty不能在IE8及更早版本,或其他非常旧版本的浏览器中使用。然而,它是String.prototype.isInList = function(){…因为使用这样简单的赋值会在String上创建一个可枚举的属性。原型,这更有可能破坏代码。

Array.indexOf

如果您使用的是现代浏览器,indexOf总是有效的。然而,对于IE8和更早的版本,你需要一个polyfill。

如果indexOf返回-1,则该项不在列表中。但是要注意,这个方法不能正确地检查NaN,虽然它可以匹配显式的undefined,但它不能像数组[1,,2]那样将缺失的元素匹配为undefined。

用于indexOf或包含在IE或任何其他缺乏支持的浏览器/版本的Polyfill

如果你不想使用像polyfill这样的服务。如上所述,您总是可以在自己的源代码中包含符合标准的自定义腻子。例如,CoreJs库有一个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;
   }
}

关于修改对象原型的注释

然而,我不认为修改字符串。prototype或Array。从长远来看,原型是个不错的策略。在JavaScript中修改对象原型可能会导致严重的错误。你需要决定这样做在你自己的环境中是否安全。主要注意的是迭代一个数组(当array。原型已添加属性)与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方法来避免这个额外的关键问题:

Use of instead of in, for (let x of arr). However, depending on the output target and the exact settings/capabilities of your down-leveling transpiler, this may not be reliable. Plus, unless you can guarantee that all of your code and third-party libraries strictly stick to this method, then for the purposes of this question you'll probably just want to use includes as stated above. Define your new properties on the prototype using Object.defineProperty(), as this will make the property (by default) non-enumerable. This only truly solves the problem if all the JavaScript libraries or modules you use also do this.

注意最后一个问题

最后,要注意,虽然填充是有意义的,修改对象原型是一个有用的策略,但这种方法偶尔仍然会出现范围问题。

In a browser, each distinct document object is its own new global scope, and in browser JS it is possible to create new documents (such as those used for off-screen rendering or to create document fragments) or to get a reference to another page's document object (such as via inter-page communication using a named-target link) so it's possible in certain (rare?) circumstances that object prototypes won't have the methods you expect them to have—though you could always run your polyfills again against the new global objects...

In Node.js, modifying prototypes of global objects may be safe, but modifying the prototypes of non-global, imported objects could lead to breakage if you ever end up with two versions of the same package being required/imported, because imports of the two versions will not expose the same objects, thus won't have the same object prototypes. That is, your code could work fine until a dependency or sub-dependency uses a different version from the one you expect, and without any of your own code changing, a simple npm install or yarn install could trigger this problem. (There are options to deal with this, such as yarn's resolutions property in the package.json, but that's not a good thing to rely on if you have other options.)


谢谢你的问题,以及使用数组的解决方案。indexOf方法。

我使用这个解决方案的代码创建了一个inList()函数,在我看来,这将使写作更简单,阅读更清晰:

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
}

我很惊讶居然没有人提到一个接受字符串和列表的简单函数。

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));

SLaks回答的简化版本也适用:

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

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

如果需要,可以像我前面描述的那样为Internet Explorer实现indexof函数。


我的解决方案的结果是这样的语法:

// 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。

优点:简单、直接、自文档化。


这是我的:

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


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'));

还有很多其他的!


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

}

我的小小贡献:

function fnListIndexOf(pList, pValue)
{
    return pList.split(",").indexOf (pValue);
}

fnListIndexOf("1,2,3,4,5,a,b,c","a")