Überprüfen Sie die Variablengleichheit anhand einer Werteliste

133

Ich überprüfe beispielsweise eine Variable fooauf Gleichheit mit einer Reihe von Werten. Beispielsweise,

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

Der Punkt ist, dass es ziemlich viel Code für solch eine triviale Aufgabe ist. Ich habe mir Folgendes ausgedacht:

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

aber auch das spricht mich nicht ganz an, weil ich den Elementen im Objekt redundante Werte geben muss.

Kennt jemand einen vernünftigen Weg, um eine Gleichheitsprüfung gegen mehrere Werte durchzuführen?

pimvdb
quelle
Ich denke, der größere Kontext muss bei der Entscheidung für so etwas berücksichtigt werden, da es wichtig ist zu wissen, warum Sie solche Vergleiche anstellen.
Pointy
Nun, in einem Spiel, das ich erstelle, überprüfe ich die Tastaturcodes, um zu entscheiden, welche Funktion aufgerufen werden soll. In verschiedenen Browsern hat ein Schlüssel anscheinend unterschiedliche Schlüsselcodes, daher muss er mit mehreren Werten verglichen werden.
Pimvdb
Überprüfen Sie den Leistungstest auf mehrere Methoden. Der logische Operator gewinnt runkit.com/pramendra/58cad911146c1c00147f8d8d
Pramendra Gupta

Antworten:

175

Sie könnten ein Array verwenden und indexOf:

if ([1,3,12].indexOf(foo) > -1)
Gumbo
quelle
1
Ich mag diesen. Es wäre sogar möglich, eine 'enthält'-Funktion durch einen Prototyp zu erstellen, um die Verwendung von> -1 zu eliminieren.
Pimvdb
1
@pimvdb: Beachten Sie, dass Sie möglicherweise eine eigene Implementierung benötigen, da diese indexOferst seit der 5. Ausgabe von ECMAScript verfügbar ist.
Gumbo
In einer anderen Antwort wird dies ebenfalls erwähnt, das wusste ich nicht, danke
pimvdb
Ist '>' irgendwie besser als '! =='?
Max Waterman
116

In ECMA2016 können Sie die Includes- Methode verwenden. Es ist der sauberste Weg, den ich je gesehen habe. (Unterstützt von allen gängigen Browsern außer IE (Polyfill befindet sich im Link)

if([1,3,12].includes(foo)) {
    // ...
}
Alister
quelle
4
Für Variablen if([a,b,c].includes(foo))oder Stringsif(['a','b','c'].includes(foo))
Hastig Zusammenstellen
für Variablen =>, if([a,b,c].includes(foo))da Anführungszeichen es zu einer Zeichenfolge machen. @HastigZusammenstellen
iambinodstha
2
@ BinodShrestha Ich denke, das habe ich geschrieben, es sei denn, ich vermisse etwas. "Für Variablen ... oder Strings ..."
Hastig Zusammenstellen
16

Mit den Antworten kam ich zu folgendem Ergebnis:

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

Es kann wie folgt aufgerufen werden:

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

Bearbeiten: Ich bin in letzter Zeit auf diesen 'Trick' gestoßen, der nützlich ist, wenn die Werte Zeichenfolgen sind und keine Sonderzeichen enthalten. Denn Sonderzeichen werden durch Flucht hässlich und sind dadurch auch fehleranfälliger.

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

Genauer gesagt überprüft dies die genaue Zeichenfolge, ist jedoch für einen einfachen Gleichheitstest komplizierter:

/^(foo|bar|something)$/.test(str);
pimvdb
quelle
5
Güte! Ich bin erstaunt, dass das funktioniert - inist ein Schlüsselwort in Javascript. Zum Beispiel führt das Ausführen function in() {}; in()zu einem Syntaxfehler, zumindest in Firefox, und ich bin mir nicht sicher, warum Ihr Code dies nicht tut. :-)
Ben Blank
3
Außerdem wird es oft als schlechte Praxis angesehen, es zu erweitern Object.prototype, da es sich auf for (foo in bar)unglückliche Weise auswirkt . Vielleicht ändern Sie es function contains(obj) { for (var i = 1; i < arguments.length; i++) if (arguments[i] === obj) return true; return false; }und übergeben Sie das Objekt als Argument?
Ben Blank
Vielen Dank für Ihre Reaktion. Der Google Closure Compiler gibt auch beim Kompilieren einen Fehler zurück, während dieser Code selbst hervorragend funktioniert. Wie auch immer, es wurde vorgeschlagen, dass eine Helferklasse diesen Job besser erledigen kann als zu erweitern, Object.prototypewie Sie auch erwähnen. Ich bevorzuge jedoch diesen Weg, da die Notation für die Überprüfung sehr foo.in(1, 2, "test", Infinity)einfach ist.
Pimvdb
Und in()das normale Definieren einer Funktion schlägt auch in Chrome fehl, aber der Prototyp funktioniert ... :)
pimvdb
3
Das Erweitern des Object.prototype ist ein Anti-Pattern und sollte nicht verwendet werden. Verwenden Sie stattdessen eine Funktion.
Vernon
9

Sie können schreiben, if(foo in L(10,20,30))wenn Sie definieren, Lzu sein

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

    return obj;
};
Elian Ebbing
quelle
Das ist sogar noch deutlicher als die früheren Antworten, danke!
Pimvdb
2
Ich halte es für ratsam zu bemerken, dass sich Prototypfunktionen auch in einem Array / Objekt befinden. Wenn also eine Funktion im Prototyp eines Arrays / Objekts entfernt wird, wird immer true zurückgegeben, wenn Sie codieren 'remove' in L(1, 3, 12), obwohl Sie dies nicht getan haben Geben Sie 'remove' an, das in die Liste aufgenommen werden soll.
Pimvdb
7

Dies ist leicht erweiterbar und lesbar:

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

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

Aber nicht unbedingt einfacher :)

orlp
quelle
Ich habe diese Methode tatsächlich verwendet, da ich neben jedem Wert einen Kommentar einfügen wollte, um zu beschreiben, worauf sich der Wert bezieht. Dies war der am besten lesbare Weg, um dies zu erreichen.
Pholcroft
@pholcroft Wenn Sie beschreiben müssen, worauf sich jeder Wert bezieht, sollten Sie eine Aufzählung oder Klasse erstellen und Ihre Eigenschaften so schreiben, dass sie beschreibende Namen haben.
red_dorian
6
var a = [1,2,3];

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

Beachten Sie, dass indexOf nicht im Kern-ECMAScript enthalten ist. Sie benötigen ein Snippet für IE und möglicherweise andere Browser, die Array.prototype.indexOf nicht unterstützen.

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;
  };
}
meder omuraliev
quelle
Es ist Mozillas Kopie direkt. War zu faul um zu verlinken. developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
meder omuraliev
Gibt es einen Grund für die Bitverschiebung, wenn Sie len definieren, wenn Sie keine Bits verschieben? Gibt es hier impliziten Zwang?
Jaredad7
3

Da die Werte, anhand derer Sie das Ergebnis überprüfen, alle eindeutig sind, können Sie auch Set.prototype.has () verwenden .

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

Ivan Sivak
quelle
2

Jetzt haben Sie vielleicht eine bessere Lösung, um dieses Szenario zu lösen, aber auf eine andere Weise, die ich bevorzugt habe.

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    
}

Ich habe die obige Lösung der indexOf-Prüfung vorgezogen, bei der Sie auch den Index überprüfen müssen.

enthält Dokumente

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

Ich mochte die akzeptierte Antwort, dachte aber, es wäre ordentlich, wenn sie auch Arrays aufnehmen könnte, und erweiterte sie folgendermaßen:

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

Sie können durch Änderung Typ Zwang entfernen ==zu ===.

Greg Perham
quelle
1

Wenn Sie Zugriff auf Unterstrich haben, können Sie Folgendes verwenden:

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

contains Früher auch in Lodash gearbeitet (vor V4), jetzt müssen Sie verwenden includes

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

Dies ist eine kleine Helfer-Arror-Funktion:

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

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

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

Mehr Infos hier ...

Sieger
quelle
Sehr guter Ansatz: Ausgehend von Ihrer Idee können Sie dies auch ohne Hilfsfunktion tun:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].some(option => option === valToCheck); // false
Giorgio Tempesta
Aber sobald ich angefangen habe, den Code zu includesoptimieren, habe ich festgestellt, dass dies die bessere Option ist, wie in der Antwort von @ alister:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].includes(valToCheck); // false
Giorgio Tempesta
0

Ich habe einfach die jQuery inArray- Funktion und ein Array von Werten verwendet, um dies zu erreichen:

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

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

if(test >= 0) // true
ScottyG
quelle