Değişken eşitliğini bir değerler listesine göre kontrol edin


133

Bir değişkeni, örneğin foobir dizi değere eşitlik için kontrol ediyorum . Örneğin,

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

Mesele şu ki, bu kadar önemsiz bir görev için oldukça fazla kod. Aşağıdakileri buldum:

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

ama aynı zamanda bu bana pek de çekici gelmiyor çünkü nesnedeki öğelere fazlalık değerler vermem gerekiyor.

Birden fazla değere karşı eşitlik kontrolü yapmanın makul bir yolunu bilen var mı?


Böyle bir şeye karar verirken daha geniş bağlamın dahil edilmesi gerektiğini düşünüyorum, çünkü neden böyle karşılaştırmalar yaptığınızı bilmek önemlidir .
Pointy

Oluşturduğum bir oyunda, hangi fonksiyonun çağrılması gerektiğine karar vermek için klavye kodlarını kontrol ediyorum. Farklı tarayıcılarda, bir anahtarın görünüşte farklı anahtar kodları vardır, bu nedenle birden çok değerle karşılaştırma yapılması gerekir.
pimvdb

birden fazla yöntem için performans testini kontrol edin, mantıksal operatör kazanır runkit.com/pramendra/58cad911146c1c00147f8d8d
Pramendra Gupta

Yanıtlar:


175

Bir dizi kullanabilirsiniz ve indexOf:

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

1
Bunu beğendim. > -1 kullanımını ortadan kaldırmak için sanırım prototip aracılığıyla bir 'içerir' işlevi oluşturmak bile mümkün olabilir.
pimvdb

1
@pimvdb: indexOfYalnızca ECMAScript 5. sürümünden itibaren mevcut olduğu için kendi uygulamanıza ihtiyaç duyabileceğinizi unutmayın .
Gumbo

Başka bir cevapta bundan bahsediliyor aslında, bunu bilmiyordum, teşekkürler
pimvdb

'>' Bir şekilde '! ==' den daha mı iyi?
Max Waterman

117

ECMA2016 olarak kullanabileceğiniz içerir yöntemi. Bu gördüğüm en temiz yol. (IE hariç tüm büyük tarayıcılar tarafından desteklenir (Polyfill bağlantıdadır)

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

4
Değişkenler if([a,b,c].includes(foo))veya dizeler içinif(['a','b','c'].includes(foo))
Hastig Zusammenstellen

değişkenler için => if([a,b,c].includes(foo))çünkü Tırnak işareti onu dizgi haline getirecektir. @HastigZusammenstellen
iambinodstha

2
@BinodShrestha Bir şeyi kaçırmıyorsam yazdıklarımın bu olduğunu düşünüyorum. "Değişkenler için .. veya dizeler ..."
Hastig Zusammenstellen

16

Verilen cevapları kullanarak şunu elde ettim:

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

Şöyle çağrılabilir:

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

Düzenleme: Son zamanlarda bu 'numara' ile karşılaştım; bu, değerler dizeler ise ve özel karakterler içermiyorsa yararlıdır. Özel karakterler için kaçış nedeniyle çirkinleşir ve bundan dolayı da hataya daha yatkındır.

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

Daha kesin olmak gerekirse, bu tam dizeyi kontrol edecektir, ancak basit bir eşitlik testi için yine daha karmaşıktır:

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

5
İyilik! inJavascript'te işe yarayan bir anahtar kelime olduğuna şaşırdım . Örneğin, çalıştırmak function in() {}; in()bir sözdizimi hatasıyla sonuçlanır, en azından Firefox'ta ve kodunuzun neden olmadığından emin değilim. :-)
Ben Blank

3
Ayrıca, talihsiz şekillerde Object.prototypeetkilediği için, genellikle uzatılması kötü bir uygulama olarak kabul edilir for (foo in bar). Belki de değiştirip function contains(obj) { for (var i = 1; i < arguments.length; i++) if (arguments[i] === obj) return true; return false; }nesneyi bir argüman olarak iletin?
Ben Blank

Tepkiniz için teşekkürler ve Google Closure Compiler, bu kodun kendisi güzelce çalışırken derleme sırasında da bir hata veriyor. Her neyse, bir yardımcı sınıfın bu işi Object.prototypesizin de bahsettiğiniz gibi genişletmekten daha iyi yapabileceği önerildi . Bununla birlikte, kontrol için notasyon güzel, sadece foo.in(1, 2, "test", Infinity)pasta kadar kolay olduğu için bu yolu tercih ediyorum .
pimvdb

Ve bir işlevi in()normal şekilde tanımlamak Chrome'da da başarısız olur, ancak prototip çalışır ... :)
pimvdb

3
Object.prototype'ı genişletmek bir anti-modeldir ve kullanılmamalıdır. Bunun yerine bir işlev kullanın.
Vernon

9

Sen yazabilir if(foo in L(10,20,30))tanımladığınız eğer Lolmak

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

    return obj;
};

Bu aslında eski cevaplardan bile daha net, teşekkürler!
pimvdb

2
Prototip işlevlerinin aynı zamanda bir dizi / nesnenin 'içinde' olduğunu belirtmek akıllıca olacaktır - bu nedenle bir dizi / nesnenin prototipinde bir 'kaldır' işlevi varsa 'remove' in L(1, 3, 12), kodlamamış olsanız da, her zaman doğru döndürür. listeye eklenecek 'kaldır'ı belirtin.
pimvdb

7

Bu, kolayca genişletilebilir ve okunabilir:

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

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

Ama illa ki daha kolay değil :)


Aslında bu yöntemi, değerin neyle ilgili olduğunu açıklamak için her değerin yanına bir yorum koymak istediğim için kullandım, bu, onu elde etmenin en okunaklı yoluydu.
pholcroft

@pholcroft, her bir değerin sizinle ilgili ne olduğunu açıklamanız gerekiyorsa, bir enum veya sınıf oluşturmalı ve özelliklerinizi açıklayıcı adlara sahip olacak şekilde yazmalısınız.
red_dorian

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

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

İndexOf'un çekirdek ECMAScript'te olmadığını unutmayın. IE ve muhtemelen Array.prototype.indexOf'u desteklemeyen diğer tarayıcılar için bir snippet'e sahip olmanız gerekir.

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

Doğrudan Mozilla'nın kopyasıdır. Bağlanmak için çok tembeldi. developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
meder omuraliev

Aslında bitleri kaydırmıyorsanız, len'i tanımlarken bit kaydırmanın bir nedeni var mı? Burada bazı örtük baskı var mı?
jaredad7

3

Ayrıca, sonucu kontrol ettiğiniz değerlerin tümü benzersiz olduğundan, Set.prototype.has () öğesini de kullanabilirsiniz .

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

Şimdi bu senaryoyu çözmek için daha iyi bir çözüme sahip olabilirsiniz, ancak tercih ettiğim başka bir yol.

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    
}

Yukarıdaki çözümü, indeksi kontrol etmeniz gereken indexOf check yerine tercih ettim.

dokümanları içerir

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

1

Kabul edilen cevabı beğendim, ancak dizileri de almasını sağlamanın güzel olacağını düşündüm, bu yüzden bunu şuna genişlettim:

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

Sen değiştirerek tipi zorlama kaldırabilirsiniz ==için ===.


1

Alt Çizgi'ye erişiminiz varsa, aşağıdakileri kullanabilirsiniz:

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

contains Lodash'ta da çalışıyordu (V4'ten önce), şimdi kullanmanız gerekiyor includes

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

1

Bu küçük bir yardımcı hata işlevidir:

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

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

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

Daha fazla bilgi burada ...


Çok iyi bir yaklaşım: fikrinizden yola çıkarak bunu yardımcı bir işlev olmadan da yapabilirsiniz:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].some(option => option === valToCheck); // false
Giorgio Tempesta

Ancak bulduğum kodu değiştirmeye başladığımda includes, bunun daha iyi bir seçenek haline geldiğini, @ alister'ın cevabında olduğu gibi:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].includes(valToCheck); // false
Giorgio Tempesta

0

Bunu gerçekleştirmek için sadece jQuery inArray işlevini ve bir dizi değer kullandım:

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

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

if(test >= 0) // true

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.