Multiple conditions in if statement on both sides of the logical operator

无人久伴 提交于 2019-11-27 08:08:04

问题


I was experimenting with having multiple arguments in an if statement on both sides of the logical operator. I first started with the || operator, which worked as expected:

var a = 'apple', b = 'banana', c = 'cherry';

if (a == 'banana' || a == 'apple' || b == 'banana' || b == 'apple') {
    console.log('example 1') // returns
}

if ((a || b) == 'banana' || (a || b) == 'apple') {
    console.log('example 2') // returns
}

if (a == ('apple' || 'banana') || b == ('apple' || 'banana')) {
    console.log('example 3') // returns
}

if ((a || b) == ('apple' || 'banana')) {
    console.log('example 4') // returns
}

So far, no unexpected results. However, when following a similar structure when replacing the || operator for the && operator, things don't quite work as I expect them to.

if ((a == 'banana' && b == 'apple') || (a == 'apple' && b == 'banana')) {
    console.log('example 5') // returns
}

if (((a || b) == 'banana') && ((a || b) == 'apple')) {
    console.log('example 6') // DOESN'T RETURN
}

if ((a || b) == 'banana') {
    console.log('example 6a') // DOESN'T RETURN - consistent with example 6
}

if ((a == ('apple' || 'banana')) && (b == ('apple' || 'banana'))) {
    console.log('example 7') // DOESN'T RETURN
}

if (a == ('apple' || 'banana')) {
    console.log('example 7a') // returns - inconsistent with example 7
}

if (b == ('apple' || 'banana')) {
    console.log('example 7b') // DOESN'T RETURN - inconsistent with example 7a
}

if ((a && b) == ('apple' || 'banana')) {
    console.log('example 8') // DOESN'T RETURN
}

if ('apple' == (a || b) && 'banana' == (a || b)) {
    console.log('example 9') // DOESN'T RETURN
}

Now, I am wondering: is there a flaw in my logic or can it just not be done this way? My aim is to write these if statements as short as possible, for the purpose of readibility and maintainability. Clearly I am just exploring possibilities.

Does anyone know any way to go about this? Especially example 7/7a/7b seems peculiar to me because it yields inconsistent results despite a similar structure [Fiddle]


回答1:


The Logical OR operator doesn't work in a way you're looking for.

Returns expr1 if it can be converted to true; otherwise, returns expr2. Thus, when used with Boolean values, || returns true if either operand is true; if both are false, returns false.

MDN

One alternative way could be make use of array's indexOf method. Just be aware it will return the index of the array element, so 0 could be a valid value also. In order to make our if statement works as expected, we have to use 0 <= ... like this:

if ( 0 <= ["apple","banana"].indexOf(a) ) { ... }

The other thing you can do is using in operator. Also as it checks only against the keys, you can leave the values empty like this:

if ( a in { "apple": "", "banana": "" } ) { ... }

If you have lot's of options, obviously it's better to do the following:

var options = {
    "apple": "",
    "banana": ""
}

if ( a in options ) { ... }

Personally I think with just two options to check, this will be more readable for a human-eye to go for two separated checks, and I think in your examples you don't really need to shorten the if statements as they're already quite short and readable in my opinion.

if ( "apple" === a || "banana" === a ) { ... }



回答2:


If you want a clean way to check if a variable equals any of a number of other variables, try using a function like this:

http://jsfiddle.net/aYRmL/

function equalsAny (first) {
    return !![].slice.call(arguments, 1).filter(function (val) {
        return first === val;
    }).length;
}

The first argument is the one being compared to the rest. Use it like this:

var a = 'banana', b = 'orange';
equalsAny(a, 'banana', 'apple'); // returns true
equalsAny('orange', a, b); // returns true

The first one above accomplishes what you were trying to do with a == ('banana' || 'apple'). The seconds accomplishes what you were trying to do with (a || b) == 'banana'.




回答3:


As an alternative solution you can use some or every:

var __slice = [].slice;

function any(a) {
  return __slice.call(arguments,1).some(function(x) {
    return a === x;
  });
}

function all(a) {
  return __slice.call(arguments,1).every(function(x) {
    return a === x;
  });
}

And use like:

// Instead of:
// if (a == 'banana' || a == 'apple' || a == 'orange')
if (any(a, 'banana', 'apple', 'orange')) {
  ...
}

// Instead of:
// if (a == 'banana' && b == 'banana' && c == 'banana')
if (all('banana', a, b, c)) {
  ...
}



回答4:


(a || b) == 'banana' always will be false because (a || b) will return a Boolean witch is not equal to a string

UPDATE : did some testing (a || b) always returns the first operand (a in this case) witch is 'apple' and not equal to 'banana'.

|| and && will give excepted result only if the both operands are Boolean or can be cased to Boolean.




回答5:


The way it's working is that a && b and a || b are always set to the value of one of the variables. a && b will always be set to the value of b unless a is false, in which case the answer must be false. Similarly a || b will be set to the value of a, unless a is false, in which case it will be set to the value of b. As elclanrs mentioned, this is because of short-circuit evaluation -- the first operand may determine the result, in which case there's no point in looking at the second operand.

When both a and b are strings, they will never be false unless the string is zero-length. So a || b will be 'apple' in your case, and a && b will be 'banana'.



来源:https://stackoverflow.com/questions/22125750/multiple-conditions-in-if-statement-on-both-sides-of-the-logical-operator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!