我有一个很长的条件语句,如下所示:
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
为之外>= 0
,还有一个不错的捷径:
if ( ~[1, 2, 3, 4].indexOf(test.type) ) {
// Do something
}
这是小提琴:http : //jsfiddle.net/HYJvK/
这是如何运作的?如果在数组中找到一个项目,则indexOf
返回其索引。如果找不到该项目,它将返回-1
。无需赘述,~
是按位NOT运算符,该运算符0
仅返回-1
。
我喜欢使用~
快捷方式,因为它比对返回值进行比较简洁。我希望JavaScript具有一个in_array
直接返回布尔值的函数(类似于PHP),但这只是一厢情愿(Update:现在可以了。称为includes
。参见上文)。请注意,jQueryinArray
共享PHP的方法签名时,实际上模仿了本机indexOf
功能(在不同情况下很有用,如果您真正追求的是索引)。
重要说明:使用波浪号快捷方式似乎引起了争议,因为有些人强烈地认为代码不够清晰,应该不惜一切代价避免使用(请参阅此答案的注释)。如果您有共同的想法,则应该坚持.indexOf(...) >= 0
解决。
稍长一点的解释:
JavaScript中的整数是带符号的,这意味着最左边的位被保留为符号位;一个标志,指示数字是正数还是负数,其中一个1
为负数。
以下是一些32位二进制格式的正数示例:
1 : 00000000000000000000000000000001
2 : 00000000000000000000000000000010
3 : 00000000000000000000000000000011
15: 00000000000000000000000000001111
现在,这些数字相同,但为负数:
-1 : 11111111111111111111111111111111
-2 : 11111111111111111111111111111110
-3 : 11111111111111111111111111111101
-15: 11111111111111111111111111110001
为什么对负数使用这种怪异的组合?简单。负数就是正数+ 1的倒数;将负数加上正数总是应该产生的0
。
为了理解这一点,让我们做一些简单的二进制算术。
这是我们将添加-1
到的方法+1
:
00000000000000000000000000000001 +1
+ 11111111111111111111111111111111 -1
-------------------------------------------
= 00000000000000000000000000000000 0
这是我们将添加-15
到的方式+15
:
00000000000000000000000000001111 +15
+ 11111111111111111111111111110001 -15
--------------------------------------------
= 00000000000000000000000000000000 0
我们如何获得这些结果?通过定期加法,我们在学校所教的方式:您从最右边的列开始,然后将所有行加起来。如果总和大于最大的一位数字(十进制为9
,而二进制为1
),则将余数转入下一列。
现在,您会注意到,在将负数添加到其正数时,不是all0
的最右边的列将始终具有两个1
s,将它们加在一起将得到2
。两个be的二进制表示形式10
,我们将携带1
到下一列,然后将0
结果放置在第一列中。左侧的所有其他列只有一行带有1
,因此1
从上一列结转的结余将再次加到2
,然后再结转...此过程重复进行,直到我们到达最左边的列,在此在1
被结转无处可去,所以它溢出和丢失,我们就只剩下0
一切都跨越。
该系统称为2的补码。您可以在此处了解更多信息:
现在,以2的补码结束的崩溃过程已经结束,您将注意到,这-1
是唯一二进制表示为1
的数字。
使用~
按位NOT运算符,可以反转给定数字中的所有位。0
从所有位取反的唯一方法是,如果从头开始使用1
。
因此,所有这一切都是漫长的说法,~n
只有0
在n
is时才会返回-1
。
您可以通过以下方式使用switch语句:
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集,然后仅调用.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条件时有2个目标。
- 简洁
- 可读性
因此,有时#1可能是最快的,但是以后我将采用#2以便于维护。根据情况的不同,我经常会选择Walter的答案。
首先,我有一个全局可用的函数作为现有库的一部分。
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循环的运行,第三部分使循环最终退出。
文章标签:if-statement , javascript
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!
评论已关闭!