根据值列表检查变量是不是相等
Posted
技术标签:
【中文标题】根据值列表检查变量是不是相等【英文标题】:Check variable equality against a list of values根据值列表检查变量是否相等 【发布时间】:2011-01-18 19:27:15 【问题描述】:我正在检查一个变量,比如foo
,是否与多个值相等。例如,
if( foo == 1 || foo == 3 || foo == 12 )
// ...
关键是对于这样一个微不足道的任务,它的代码相当多。我想出了以下几点:
if( foo in 1: 1, 3: 1, 12: 1 )
// ...
但这并不完全吸引我,因为我必须为对象中的项目赋予冗余值。
有人知道对多个值进行相等性检查的体面方法吗?
【问题讨论】:
我认为在决定这样的事情时需要考虑更大的背景,因为了解为什么进行此类比较非常重要。 好吧,在我正在创建的游戏中,我正在检查键盘代码以确定应该调用什么函数。在不同的浏览器中,一个键看起来有不同的键码,因此需要与多个值进行比较。 检查多个方法的性能测试,逻辑运算符获胜runkit.com/pramendra/58cad911146c1c00147f8d8d 这是一个常见的重复目标,用于询问为什么variable === value1 || value2
不起作用。对于那些想知道为什么的人:||
和 &&
与 short-circuit evaluation 一起使用;每个操作数要么是truthy or falsy。 x === 1 || 2
表示 (x === 1) || (2)
并且是 true
或 2
,因为 ||
导致第一个真值或最后一个假值操作数,而 x === "a" || "b"
是 true
或 "b"
。由于true
、2
和"b"
都是真值,因此将它们置于if
条件中等效于if(true)
。只需使用[ "a", "b" ].includes(x)
。
【参考方案1】:
你可以使用数组和indexOf
:
if ([1,3,12].indexOf(foo) > -1)
【讨论】:
我喜欢这个。我猜甚至可以通过原型创建一个“包含”函数,从而消除 > -1 的使用。 @pimvdb:请注意,您可能需要自己的实现,因为indexOf
仅在 ECMAScript 第 5 版之后才可用。
'>' 是否比 '!==' 更好?
你可以用~
操作符代替> -1
:if ( ~[...].indexOf(foo) ) ...
@MaxWaterman 首先,绝对没有必要检查结果的类型,因为indexOf
总是返回一个数字,所以!=
就足够了。而且>
更短,所以是的,它更好【参考方案2】:
在 ECMA2016 中,您可以使用 includes 方法。这是我见过的最干净的方式。 (所有主流浏览器都支持)
if([1,3,12].includes(foo))
// ...
【讨论】:
对于变量if([a,b,c].includes(foo))
或字符串if(['a','b','c'].includes(foo))
for variables => if([a,b,c].includes(foo))
因为引号将使其成为字符串。 @HastigZusammenstellen
@BinodShrestha 我想这就是我写的,除非我遗漏了什么。 “对于变量……或字符串……”【参考方案3】:
使用提供的答案,我得到了以下结果:
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);
【讨论】:
天哪!我很惊讶它的工作原理——in
是 javascript 中的一个关键字。例如,运行function in() ; in()
会导致语法错误,至少在 Firefox 中是这样,我不确定为什么您的代码不会。 :-)
此外,扩展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;
并将对象作为参数传递?
扩展 Object.prototype 是一种反模式,不应使用。请改用函数。
如上所述扩展Object.prototype
这种方式有严重的缺点,可能会导致许多错误。如果你确实想扩展Object.prototype
,请始终通过Object.defineProperty
进行扩展,而无需在描述符中设置enumerable
。
@BenBlank - 仅供参考,使用关键字作为文字属性名称在第 5 版规范(2009 年 12 月)中变得有效,这就是 x.in()
起作用的原因。在第 5 版之前,您必须使用计算属性名称 (x["in"]()
)。【参考方案4】:
现在您可能有更好的解决方案来解决这种情况,但我更喜欢其他方式。
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 检查您还需要检查索引的地方。
includes docs
if ( arr.indexOf( foo ) !== -1 )
【讨论】:
【参考方案5】:这很容易扩展和阅读:
switch (foo)
case 1:
case 3:
case 12:
// ...
break
case 4:
case 5:
case 6:
// something else
break
但不一定更容易:)
【讨论】:
我实际上使用了这种方法,因为我想在每个值旁边放一个注释来描述值相关的内容,这是实现它的最易读的方式。 @pholcroft 如果您需要描述每个值与您相关的内容,您应该创建一个枚举或类,并将您的属性编写为具有描述性的名称。【参考方案6】:如果您将L
定义为,则可以编写if(foo in L(10,20,30))
var L = function()
var obj = ;
for(var i=0; i<arguments.length; i++)
obj[arguments[i]] = null;
return obj;
;
【讨论】:
我认为说原型函数也在数组/对象中是谨慎的 - 所以如果数组/对象的原型中有一个函数 'remove' ,它将总是返回 true 如果你编码'remove' in L(1, 3, 12)
,虽然你没有指定'remove'被放入列表中。【参考方案7】:
var a = [1,2,3];
if ( a.indexOf( 1 ) !== -1 )
请注意,indexOf 不在核心 ECMAScript 中。您需要为 IE 和其他不支持 Array.prototype.indexOf 的浏览器提供 sn-p。
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的copy。懒得链接了。 developer.mozilla.org/en/JavaScript/Reference/Global_Objects/… 如果您实际上没有移位位,那么在定义 len 时是否存在位移位的原因?这里有什么隐含的强制吗? “请注意,indexOf 不在核心 ECMAScript 中。” 它是在 2009 年 12 月的第 5 版规范中添加的。【参考方案8】:此外,由于您检查结果所依据的值都是唯一的,您也可以使用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) );
【讨论】:
【参考方案9】:我喜欢接受的答案,但认为让它也能接受数组会很整洁,所以我将其扩展为:
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
您可以通过将==
更改为===
来移除类型强制。
【讨论】:
【参考方案10】:如果您有权访问下划线,则可以使用以下内容:
if (_.contains([1, 3, 12], foo))
// ...
contains
以前也可以在 Lodash 中工作(在 V4 之前),现在你必须使用 includes
if (_.includes([1, 3, 12], foo))
handleYellowFruit();
【讨论】:
【参考方案11】:我只是使用 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
【讨论】:
【参考方案12】:这是一个小辅助箭头函数:
const letters = ['A', 'B', 'C', 'D'];
function checkInList(arr, val)
return arr.some(arrVal => val === arrVal);
checkInList(letters, 'E'); // false
checkInList(letters, 'A'); // true
More info here...
【讨论】:
非常好的方法:从您的想法开始,您也可以在没有辅助函数的情况下完成: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
【参考方案13】:
对于您经常比较的较大值列表,首先构造一个Set
并使用Set#has
进行恒定时间检查可能比Array#includes
以线性时间运行更为理想。
const values = new Set([1, 2, 12]);
if(values.has(foo))
// do something
【讨论】:
【参考方案14】:使用 ES6 语法你可以做到:
Object.prototype.in = function (...args)
return args.includes(this.valueOf());
顺便也检查深度相等。需要 valueOf() 方法,因为 this 是一个对象。
【讨论】:
【参考方案15】:对于后代,您可能希望使用正则表达式作为替代方案。浏览器支持也很好(参考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>');
【讨论】:
以上是关于根据值列表检查变量是不是相等的主要内容,如果未能解决你的问题,请参考以下文章