Перевірте рівність змінної щодо списку значень


133

Я перевіряю змінну, скажімо foo, на рівність ряду значень. Наприклад,

if( foo == 1 || foo == 3 || foo == 12 ) {
    // ...
}

Справа в тому, що це досить багато коду для такого тривіального завдання. Я придумав таке:

if( foo in {1: 1, 3: 1, 12: 1} ) {
    // ...
}

але це також мені зовсім не подобається, тому що я повинен надати зайві значення предметам в об'єкті.

Хтось знає гідний спосіб зробити перевірку рівності проти кількох значень?


Я думаю, що для вирішення чогось подібного потрібно брати участь більш широкий контекст, тому що важливо знати, чому ви робите такі порівняння.
Пойні

Ну, в грі, яку я створюю, я перевіряю коди клавіатури, щоб вирішити, яку функцію слід викликати. У різних браузерах ключовий ключ має різні коди ключів, отже, необхідність порівнювати з кількома значеннями.
pimvdb

перевірити перевірку працездатності на кілька методів, логічний оператор виграє runkit.com/pramendra/58cad911146c1c00147f8d8d
Pramendra Gupta

Відповіді:


175

Ви можете використовувати масив і indexOf:

if ([1,3,12].indexOf(foo) > -1)

1
Мені це подобається. Я б навіть міг створити функцію 'містить' через прототип, я думаю, щоб виключити використання> -1.
pimvdb

1
@pimvdb: Зауважте, що вам може знадобитися власна реалізація, indexOfяка доступна лише з ECMAScript 5-го видання.
Gumbo

В іншій відповіді це згадується також і справді, я цього не знав, спасибі
pimvdb

Чи '>' якось краще, ніж '! =='?
Макс Вотерман

117

У ECMA2016 ви можете використовувати включає в себе метод. Це найчистіший спосіб, який я бачив. (Підтримується всіма основними браузерами, крім IE (Polyfill знаходиться за посиланням)

if([1,3,12].includes(foo)) {
    // ...
}

4
Для змінних if([a,b,c].includes(foo))або рядківif(['a','b','c'].includes(foo))
Hastig Zusammenstellen

для змінних => if([a,b,c].includes(foo))тому, що лапка зробить її рядком. @HastigZusammenstellen
iambinodstha

2
@BinodShrestha Я думаю, що це я написав, якщо я щось не пропускаю. "Для змінних .. або рядків ..."
Hastig Zusammenstellen

16

Використовуючи надані відповіді, я закінчив таке:

Object.prototype.in = function() {
    for(var i=0; i<arguments.length; i++)
       if(arguments[i] == this) return true;
    return false;
}

Це можна назвати так:

if(foo.in(1, 3, 12)) {
    // ...
}

Редагувати: останнім часом я натрапив на цей "трюк", який корисний, якщо значення є рядками та не містять спеціальних символів. Для спеціальних символів це стає некрасивим через втечу, а також більш схильне до помилок через це.

/foo|bar|something/.test(str);

Якщо бути точнішим, це перевірятиме точний рядок, але знову ж таки складніше для простого тесту на рівність:

/^(foo|bar|something)$/.test(str);

5
Добро! Я вражений тим, що працює - inце ключове слово в JavaScript. Наприклад, запуск function in() {}; in()результатів у синтаксичній помилці, принаймні, у Firefox, і я не впевнений, чому ваш код цього не робить. :-)
Бен Бланк

3
Крім того, часто вважається поганою практикою розширення Object.prototype, оскільки це впливає for (foo in bar)невдало. Можливо, змінити його function contains(obj) { for (var i = 1; i < arguments.length; i++) if (arguments[i] === obj) return true; return false; }і передати об’єкт як аргумент?
Бен Бланк

Дякуємо за вашу реакцію, і компілятор закриття Google також повертає помилку під час компіляції, поки сам цей код працює чудово. У будь-якому випадку, було висловлено припущення, що клас-помічник може виконати цю роботу краще, ніж розширити, Object.prototypeяк ви також згадуєте. Однак я віддаю перевагу саме так, оскільки позначення для перевірки є чудовими, справедливими foo.in(1, 2, "test", Infinity), простими, як пиріг.
pimvdb

І визначити функцію in()звичайний спосіб теж не вдається для Chrome, але прототип працює ... :)
pimvdb

3
Розширення Object.prototype є анти-шаблоном і його не слід використовувати. Замість цього використовуйте функцію.
Вернон

9

Ви можете написати, if(foo in L(10,20,30))якщо визначите, Lщо є

var L = function()
{
    var obj = {};
    for(var i=0; i<arguments.length; i++)
        obj[arguments[i]] = null;

    return obj;
};

Це навіть зрозуміліше, ніж колишні відповіді насправді, дякую!
pimvdb

2
Я думаю, що доцільно зауважити, що функції прототипу також є "в" масиві / об'єкті, тому якщо в прототипі масиву / об'єкта є функція "видалити", вона завжди повернеться істиною, якщо ви введете код 'remove' in L(1, 3, 12), хоча ви цього не зробили вкажіть "видалити", який слід включити до списку.
pimvdb

7

Це легко розширюється та читається:

switch (foo) {
    case 1:
    case 3:
    case 12:
        // ...
        break

    case 4:
    case 5:
    case 6:
        // something else
        break
}

Але не обов’язково простіше :)


Я фактично використовував цей метод, оскільки хотів поставити коментар поруч із кожним значенням, щоб описати, з чим пов’язане значення, це був найбільш читаний спосіб його досягнення.
pholcroft

@pholcroft, якщо вам потрібно описати те, що стосується кожного значення, ви повинні створити перерахунок або клас та написати свої властивості, щоб вони мали описові імена.
red_dorian

6
var a = [1,2,3];

if ( a.indexOf( 1 ) !== -1 ) { }

Зауважте, що indexOf не знаходиться в основному ECMAScript. Вам потрібно мати фрагмент для IE та, можливо, інших браузерів, які не підтримують Array.prototype.indexOf.

if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(searchElement /*, fromIndex */)
  {
    "use strict";

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

    var t = Object(this);
    var len = t.length >>> 0;
    if (len === 0)
      return -1;

    var n = 0;
    if (arguments.length > 0)
    {
      n = Number(arguments[1]);
      if (n !== n)
        n = 0;
      else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
        n = (n > 0 || -1) * Math.floor(Math.abs(n));
    }

    if (n >= len)
      return -1;

    var k = n >= 0
          ? n
          : Math.max(len - Math.abs(n), 0);

    for (; k < len; k++)
    {
      if (k in t && t[k] === searchElement)
        return k;
    }
    return -1;
  };
}

Це копія Mozilla безпосередньо. Занадто ліниво було зв’язуватися. developer.mozilla.org/uk/JavaScript/Reference/Global_Objects/…
meder omuraliev

Чи є причина бітсифта, коли ви визначаєте len, якщо ви насправді не зміщуєте біти? Чи відбувається тут якийсь неявний примус?
jaredad7

3

Крім того, оскільки значення, за якими ви перевіряєте результат, унікальні, ви можете також використовувати Set.prototype.has () .

var valid = [1, 3, 12];
var goodFoo = 3;
var badFoo = 55;

// Test
console.log( new Set(valid).has(goodFoo) );
console.log( new Set(valid).has(badFoo) );


2

Тепер у вас може бути краще рішення для вирішення цього сценарію, але інший спосіб, який я віддав перевагу.

const arr = [1,3,12]
if( arr.includes(foo)) { // it will return true if you `foo` is one of array values else false
  // code here    
}

Я віддав перевагу вище рішення над indexOf перевірити, де вам також потрібно перевірити індекс.

включає документи

if ( arr.indexOf( foo ) !== -1 ) { }

1

Мені сподобалася прийнята відповідь, але я подумав, що було б акуратно дозволити їй також приймати масиви, тому я розширив її до цього:

Object.prototype.isin = function() {
    for(var i = arguments.length; i--;) {
        var a = arguments[i];
        if(a.constructor === Array) {
            for(var j = a.length; j--;)
                if(a[j] == this) return true;
        }
        else if(a == this) return true;
    }
    return false;
}

var lucky = 7,
    more = [7, 11, 42];
lucky.isin(2, 3, 5, 8, more) //true

Ви можете видалити примус типу, перейшовши ==на ===.


1

Якщо у вас є доступ до підкреслення, ви можете скористатися наступним:

if (_.contains([1, 3, 12], foo)) {
  // ...
}

contains раніше працював і в Лодаші (до V4), тепер вам доведеться користуватися includes

if (_.includes([1, 3, 12], foo)) {
  handleYellowFruit();
}

1

Це невелика функція асистента помічників:

const letters = ['A', 'B', 'C', 'D'];

function checkInList(arr, val) {
  return arr.some(arrVal => val === arrVal);
}

checkInList(letters, 'E');   // false
checkInList(letters, 'A');   // true

Більше інформації тут ...


Дуже вдалий підхід: виходячи зі своєї ідеї, ви також можете це зробити без допоміжної функції:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].some(option => option === valToCheck); // false
Джорджіо Темпеста

Але як тільки я почав підробляти код, я виявив, що він includesстає кращим варіантом, як у відповіді @ alister:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].includes(valToCheck); // false
Джорджіо Темпеста

0

Для цього я просто використав функцію jQuery inArray та масив значень:

myArr = ["A", "B", "C", "C-"];

var test = $.inArray("C", myArr)  
// returns index of 2 returns -1 if not in array

if(test >= 0) // true

-4

Для нащадків ви можете використовувати регулярні вирази як альтернативу. Досить хороша підтримка браузера (див. Https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match#Browser_compatibility )

Спробуйте це

if (foo.toString().match(/^(1|3|12)$/)) {
    document.write('Regex me IN<br>');
} else {
    document.write('Regex me OUT<br>');
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.