我有一个很长的条件语句,如下所示:
if(test.type == 'itema' || test.type == 'itemb' || test.type == 'itemc' || test.type == 'itemd'){
// do something.
}
我想知道是否可以将此表达式/语句重构为更简洁的形式。
关于如何实现这一目标的任何想法?
我有一个很长的条件语句,如下所示:
if(test.type == 'itema' || test.type == 'itemb' || test.type == 'itemc' || test.type == 'itemd'){
// do something.
}
我想知道是否可以将此表达式/语句重构为更简洁的形式。
关于如何实现这一目标的任何想法?
将您的值放入数组中,并检查您的项目是否在数组中:
if ([1, 2, 3, 4].includes(test.type)) {
// Do something
}
如果你支持的浏览器没有这个Array#includes
方法,你可以使用这个 polyfill。
~
波浪号快捷方式的简短说明:更新:既然我们现在有了这个
includes
方法,那么再使用~
hack 就没有意义了。只为那些有兴趣了解它的工作原理和/或在其他代码中遇到过它的人保留它。
不是检查indexOf
is的结果,而是>= 0
有一个不错的小捷径:
if ( ~[1, 2, 3, 4].indexOf(test.type) ) {
// Do something
}
这是小提琴:http: //jsfiddle.net/HYJvK/
这是如何运作的?如果在数组中找到项目,则indexOf
返回其索引。如果未找到该项目,它将返回-1
。无需过多介绍, the~
是一个按位 NOT 运算符,它将0
仅返回 for -1
。
我喜欢使用~
快捷方式,因为它比比较返回值更简洁。我希望 JavaScript 有一个in_array
直接返回布尔值的函数(类似于 PHP),但这只是一厢情愿的想法(更新:现在可以了。它被称为includes
. 见上文)。请注意,jQueryinArray
在共享 PHP 的方法签名的同时,实际上模仿了本机indexOf
功能(如果索引是您真正追求的,这在不同情况下很有用)。
重要提示:使用波浪号快捷方式似乎充满争议,因为有些人强烈认为代码不够清晰,应该不惜一切代价避免使用(请参阅此答案的评论)。如果你分享他们的观点,你应该坚持.indexOf(...) >= 0
解决方案。
JavaScript 中的整数是有符号的,也就是说最左边的位被保留为符号位;一个标志,指示数字是正数还是负数,a1
为负数。
以下是一些 32 位二进制格式的正数示例:
1 : 00000000000000000000000000000001
2 : 00000000000000000000000000000010
3 : 00000000000000000000000000000011
15: 00000000000000000000000000001111
现在这里是相同的数字,但为负数:
-1 : 11111111111111111111111111111111
-2 : 11111111111111111111111111111110
-3 : 11111111111111111111111111111101
-15: 11111111111111111111111111110001
为什么这些负数的奇怪组合?简单的。负数只是正数 + 1 的倒数;将负数加到正数应该总是 yield 0
。
为了理解这一点,让我们做一些简单的二进制算术。
以下是我们将如何添加-1
到+1
:
00000000000000000000000000000001 +1
+ 11111111111111111111111111111111 -1
-------------------------------------------
= 00000000000000000000000000000000 0
以下是我们将如何添加-15
到+15
:
00000000000000000000000000001111 +15
+ 11111111111111111111111111110001 -15
--------------------------------------------
= 00000000000000000000000000000000 0
我们如何得到这些结果?通过定期加法,就像我们在学校所教的那样:从最右边的一列开始,然后将所有行加起来。如果总和大于最大的一位数(十进制为9
,但二进制为1
),我们将余数移至下一列。
现在,您会注意到,当将一个负数添加到它的正数时,不是所有0
s 的最右边的列将始终有两个1
s,当它们相加时将导致2
。两个的二进制表示10
,我们将1
带到下一列,并将0
结果 a 放在第一列。左边的所有其他列只有一行带有 a 1
,因此1
从前一列结转的值将再次加起来2
,然后将结转...这个过程不断重复,直到我们到达最左边的列,其中被1
结转的无处可去,因此溢出并丢失,我们只剩下0
s。
这个系统被称为2's Complement。您可以在此处阅读有关此内容的更多信息:
现在 2 的补码速成课程已经结束,您会注意到这-1
是唯一一个二进制表示为1
' 的数字。
使用~
按位非运算符,给定数字中的所有位都被反转。从反转所有位中恢复过来的唯一方法0
是,如果我们从1
' 开始。
所以,所有这一切都是一种冗长的说法,只有在is~n
时才会返回。0
n
-1
您可以将 switch 语句与fall thru 一起使用:
switch (test.type) {
case "itema":
case "itemb":
case "itemc":
case "itemd":
// do something
}
使用科学:你应该按照 idfah 所说的去做,这样可以在保持代码简短的同时获得最快的速度:
~
这比方法快
var x = test.type;
if (x == 'itema' ||
x == 'itemb' ||
x == 'itemc' ||
x == 'itemd') {
//do something
}
http://jsperf.com/if-statements-test-techsin (顶部:Chrome,底部:Firefox)
结论 :
如果可能性很小,并且您知道某些可能性比您获得最大性能的可能性更大if ||
,switch fall through
和if(obj[keyval])
。
如果可能性很多,并且其中任何一个都可能是最常发生的一个,换句话说,您无法知道哪一个最有可能发生,而不是您从对象查找中获得最大的性能if(obj[keyval])
以及regex
是否合适。
http://jsperf.com/if-statements-test-techsin/12
如果有新的东西出现,我会更新。
如果您要与字符串进行比较并且存在模式,请考虑使用正则表达式。
否则,我怀疑试图缩短它只会混淆你的代码。考虑简单地包装线条以使其美观。
if (test.type == 'itema' ||
test.type == 'itemb' ||
test.type == 'itemc' ||
test.type == 'itemd') {
do something.
}
var possibilities = {
"itema": 1,
"itemb": 1,
"itemc": 1,
…};
if (test.type in possibilities) { … }
将对象用作关联数组是很常见的事情,但由于 JavaScript 没有原生集合,您也可以将对象用作廉价集合。
if( /^item[a-d]$/.test(test.type) ) { /* do something */ }
或者如果项目不是那么统一,那么:
if( /^(itema|itemb|itemc|itemd)$/.test(test.type) ) { /* do something */ }
很好的答案,但是您可以通过将其中一个包装在函数中来使代码更具可读性。
这是一个复杂的 if 语句,当您(或其他人)在一年内阅读代码时,您将通过扫描找到该部分以了解正在发生的事情。具有这种业务逻辑级别的语句将导致您在确定要测试的内容时绊倒几秒钟。像这样的代码,将允许您继续扫描。
if(CheckIfBusinessRuleIsTrue())
{
//Do Something
}
function CheckIfBusinessRuleIsTrue()
{
return (the best solution from previous posts here);
}
明确命名您的函数,以便立即清楚您正在测试的内容,并且您的代码将更容易扫描和理解。
您可以将所有答案放入Javascript Set中,然后调用.contains()
该集合。
您仍然必须声明所有内容,但内联调用会更短。
就像是:
var itemSet = new Set(["itema","itemb","itemc","itemd"]);
if( itemSet.contains( test.type ){}
我最喜欢的实现这一点的方法之一是使用诸如 underscore.js 之类的库...
var isItem = _.some(['itema','itemb','itemc','itemd'], function(item) {
return test.type === item;
});
if(isItem) {
// One of them was true
}
我发现的另一种方式或另一种很棒的方式是......
if ('a' in oc(['a','b','c'])) { //dosomething }
function oc(a)
{
var o = {};
for(var i=0;i<a.length;i++) o[a[i]]='';
return o;
}
当然,正如您所看到的,这使事情更进一步,并使它们易于遵循逻辑。
http://snook.ca/archives/javascript/testing_for_a_v
使用 ~ && || 等运算符 ((),()) ~~ 仅当您的代码稍后中断时才可以。你不知道从哪里开始。所以可读性很大。
如果你必须,你可以缩短它。
('a' in oc(['a','b','c'])) && statement;
('a' in oc(['a','b','c'])) && (statements,statements);
('a' in oc(['a','b','c']))?statement:elseStatement;
('a' in oc(['a','b','c']))?(statements,statements):(elseStatements,elseStatements);
如果你想做逆
('a' in oc(['a','b','c'])) || statement;
只需使用switch
语句而不是if
语句:
switch (test.type) {
case "itema":case "itemb":case "itemc":case "itemd":
// do your process
case "other cases":...:
// do other processes
default:
// do processes when test.type does not meet your predictions.
}
Switch
也比比较一个if
对于非常长的字符串列表,这个想法会节省一些字符(并不是说我会在现实生活中推荐它,但它应该可以工作)。
选择一个您知道不会出现在 test.type 中的字符,将其用作分隔符,将它们全部粘贴到一个长字符串中并搜索:
if ("/itema/itemb/itemc/itemd/".indexOf("/"+test.type+"/")>=0) {
// doSomething
}
如果您的字符串碰巧受到进一步限制,您甚至可以省略分隔符...
if ("itemaitembitemcitemd".indexOf(test.type)>=0) {
// doSomething
}
...但在这种情况下你必须小心误报(例如,“embite”会在那个版本中匹配)
为了可读性,为测试创建一个函数(是的,一个单行函数):
function isTypeDefined(test) {
return test.type == 'itema' ||
test.type == 'itemb' ||
test.type == 'itemc' ||
test.type == 'itemd';
}
然后调用它:
…
if (isTypeDefined(test)) {
…
}
...
我认为在编写这种 if 条件时有两个目标。
因此,有时#1 可能是最快的,但我会选择#2 以便稍后进行维护。根据情况,我经常会选择沃尔特答案的变体。
首先,我有一个全局可用的函数作为我现有库的一部分。
function isDefined(obj){
return (typeof(obj) != 'undefined');
}
然后当我真的想运行一个类似于你的 if 条件时,我会创建一个包含有效值列表的对象:
var validOptions = {
"itema":1,
"itemb":1,
"itemc":1,
"itemd":1
};
if(isDefined(validOptions[test.type])){
//do something...
}
它不像 switch/case 语句那么快,并且比其他一些示例更冗长,但我经常在代码的其他地方重用该对象,这非常方便。
在上面制作的一个 jsperf 示例上,我添加了这个测试和一个变体来比较速度。http://jsperf.com/if-statements-test-techsin/6我注意到的最有趣的事情是,Firefox 中的某些测试组合甚至比 Chrome 快得多。
这可以通过一个简单的 for 循环来解决:
test = {};
test.type = 'itema';
for(var i=['itema','itemb','itemc']; i[0]==test.type && [
(function() {
// do something
console.log('matched!');
})()
]; i.shift());
我们使用 for 循环的第一部分来初始化您希望匹配的参数,第二部分用于停止 for 循环运行,第三部分用于导致循环最终退出。