Why does this fail?
The way I read this code is "if either a or b or c equals three, then the statement is true". But apparently JavaScript disagrees. Why?
function test() {
var a = 'one';
var b = 'two';
var c = 'three';
return ( ( a || b || c ) === 'three' );
}
EDIT: am aware of the fact that i need to evaluate each expression separately, but was looking for a quicker way to write it. any suggestions will be welcome.
Your reading of the code is incorrect. Translated to a different form:
if (a) {
return a === "three";
}
if (b) {
return b === "three";
}
if (c) {
return c === "three";
}
The subexpression (a || b || c) returns the first of a, b, or c that is not "falsy". That's a, because its value is "one", so that's the overall value that's compared to "three".
The expression ( a || b || c ) returns anything that is truthy on the first-come-first served basis.
Here a is truthy and hence used. If a is falsey b will be used. If it is falsey too, c will be used.
So, you always end up comparing "one" == "three" since strings are considered truthy. You can make use of Array.some in this case, which does what you want or how you want it to behave, in your words
"if either a or b or c equals three, then the statement is true"
return [a,b,c].some(function(str){
return str == "three";
});
This evaluates to is a, b, or c (which will be true or false) the string-equivalent of "three". Which will always be false.
In order to achieve what you want, you need
return (a === 'three') || (b === 'three') || (c === 'three');
Related
I have a situation in my code where I have several conditions for 3 variables, let's say a, b and c.
I've implemented else if conditions for each case when one of three is false and for when all three are true and for when all three are false. But the problem is that I need to implement conditions also for when 2 out of 3 are false and following the order of a, b and c I need to show specific message for the first in order that is false.
For example, a becomes false, then b becomes false and c remains true, I need to show a specific message for a false. Other case: when b becomes false then a becomes false and c remains true, I need to show a specific message for a false, when c becomes false and b becomes false, I need to show a specific message for b.
How can this be achieved?
Code example
if (a && b && c) {
setOrder(format(order));
} else if (!a && b && c) {
setOrder("orderAlternateNumber");
} else if (!b && a && c) {
setOrder("orderNewNumber");
} else if (!c && a && b) {
setOrder("someOtherNumber");
} else if (!c && !a && !b) {
setOrder("");
}
You can combine these variables into a single number with ones and zeroes and use a simple dictionary lookup for the order parameter:
let n = 1000 + (a * 100) + (b * 10) + (c * 1)
order = {
1111: format(order), // true,true,true,
1011: "orderAlternateNumber", // false,true,true
1101: "orderNewNumber", // true,false,true etc...
1110: "someOtherNumber",
1000: '',
}
setOrder(order[n])
I am not entirely sure what your scenario is, you example is somewhat vague because you don't give a lot information about your actual issue. However based on:
For example, a becomes false, then b becomes false and c remains true, I need to show a specific message for a false.
I would suggest the following. Instead of checking all combinations a, b and c. You can also check them separately.
let error;
if (!a) error ??= "something wrong with a";
if (!b) error ??= "something wrong with b";
if (!c) error ??= "something wrong with c";
if (error) {
// do something with error message
} else {
// handle success
}
The above stores a single error message depending on the first error it encounters. ??= only assigns a value if the current value if nullish. But you could also collect them by storing them in an array.
const errors = [];
if (!a) errors.push("something wrong with a");
// ...
if (errors.length != 0) {
This might not be what your looking for, it's hard to say what is since you withhold your actual scenario.
On the function that changes a, b and c, you need to have a condition.
If one of them is going to be set to false, you have to check if another one, and only one is already false. If there is another false, you can set the message according to this one and commit the change for the second parameter to be false.
If im not clear, you might want to add code example for the function that controls a, b and c for my better understanding.
I want to write an if/else statement that tests if the value of a text input does NOT equal either one of two different values. Like this (excuse my pseudo-English code):
var test = $("#test").val();
if (test does not equal A or B){
do stuff;
}
else {
do other stuff;
}
How do I write the condition for the if statement on line 2?
Think of ! (negation operator) as "not", || (boolean-or operator) as "or" and && (boolean-and operator) as "and". See Operators and Operator Precedence.
Thus:
if(!(a || b)) {
// means neither a nor b
}
However, using De Morgan's Law, it could be written as:
if(!a && !b) {
// is not a and is not b
}
a and b above can be any expression (such as test == 'B' or whatever it needs to be).
Once again, if test == 'A' and test == 'B', are the expressions, note the expansion of the 1st form:
// if(!(a || b))
if(!((test == 'A') || (test == 'B')))
// or more simply, removing the inner parenthesis as
// || and && have a lower precedence than comparison and negation operators
if(!(test == 'A' || test == 'B'))
// and using DeMorgan's, we can turn this into
// this is the same as substituting into if(!a && !b)
if(!(test == 'A') && !(test == 'B'))
// and this can be simplified as !(x == y) is the same as (x != y)
if(test != 'A' && test != 'B')
ECMA2016 answer, especially good when checking against multiple values:
if (!["A","B", ...].includes(test)) {}
In general it would be something like this:
if(test != "A" && test != "B")
You should probably read up on JavaScript logical operators.
I do that using jQuery
if ( 0 > $.inArray( test, [a,b] ) ) { ... }
For a larger number of values that is checked against often, it may be more efficient to check if the value does not exist in a Set.
const values = new Set(["a", "b"]);
if(!values.has(someValue)){
// do something
} else {
// do something else
}
var test = $("#test").val();
if (test != 'A' && test != 'B'){
do stuff;
}
else {
do other stuff;
}
You used the word "or" in your pseudo code, but based on your first sentence, I think you mean and. There was some confusion about this because that is not how people usually speak.
You want:
var test = $("#test").val();
if (test !== 'A' && test !== 'B'){
do stuff;
}
else {
do other stuff;
}
This can be done with a switch statement as well. The order of the conditional is reversed but this really doesn't make a difference (and it's slightly simpler anyways).
switch(test) {
case A:
case B:
do other stuff;
break;
default:
do stuff;
}
Just read on Javascript book by David Flanagan this case:
(a = b) == 0
But I can't see the use of this. Could be like this?
var b = 0;
var a = b;
if (a == 0) ...
Thanks
Your interpretation is correct. The assignment returns the assigned value.
It just assigns b to a. If b (and consequently a) is 0, the condition is true.
It's evaluated in this order:
(a = b) == 0
-------
^ assign the value of b to a
------------
Check if the value of a equals 0
Pretty much it's the same with:
a = b;
if (a == 0) {
// do something
}
It's just a shorter version. Don't forget to declare the variables, otherwise they will be appended to the global namespace.
This is the short form. Means:
Assign b to a
Then compare the value.
(a = b) assigns b to a and is furthermore an expression with the new value of a.
So (a = b) == 0 is an expression that assigns b to a and is evaluates its relational equality to 0.
In C and C++ you'll often see it written as if (!(a = b)). Some folk find such a form obfuscating as it's a stone's-throw away from the considerably different if(!(a == b)).
In C I know true and false evaluate to 1 and 0 respectively. show in this case just prints to the screen... Not sure what's going on here. I'm expecting to get true back. This 1 is messing up my karma.
show(1 && true);
true
show(true && 1);
1
Simply put - that's how && is defined. In Javascript, a && b returns a if a is falsy and b if a is truthy.
Conversely a || b returns a if a is truthy and b if a is falsy.
This makes sense intuitively - if a is false in a && b, then why bother reading the rest of the expression? You already know the whole thing is false. So just return false. But Javascript makes the decision to return a, which is falsy, instead of making up the value false to return out of nowhere.
This is based on short-circuit evaluation common to all C-style languages.
It allows for much expressiveness in Javascript. For instance this pattern:
var foo = function(opts) {
opts = opts || {}
// ...
}
Implements an optional parameter opts. If opts is not passed in at all, opts = opts || {} will set opts to {}, so the rest of the code does not have to know opts wasn't passed.
In long-hand it is equivalent to the following:
var x = a || b; // is equivalent to
var x;
if(a) {
x = a;
}
else {
x = b;
}
and
var y = a && b; // is equivalent to
var y;
if(!a) {
y = a;
}
else {
y = b;
}
Therefore Javascript can be much more terse than C or Java, because simple if statements can be replaced by || or && entirely. Sometimes this makes the code more terse and less readable and more like Perl, other times it allows for new Javascript patterns, like opts = opts || {}.
Another use is in patterns like
var displayName = user.fullname || user.email;
Which means "use the full name if available; if not, fall back to email." I personally find this expressive and readable, but it's arguably terse and obscure depending on which part of the Javascript community you hail from. Because of examples like this, and essentially the fact that truthy values are far more diverse then falsy values, using short-circuit || is much more common than short-circuit &&, as in your question.
var c = false;
if(c=[] && c.length==0)alert('hi');
hi is not alerted because c is still false when it executes the second operand of &&, can someone explain how the boolean operands in if condition are executed and in what order?
I believe this is just a precedence issue - && is binding tighter than =. Your code is equivalent to:
if (c = ([] && c.length == 0))
{
alert('hi');
}
So it's assigning c the value false rather than the empty array.
Try this instead:
if ((c = []) && c.length == 0)
{
alert('hi');
}
EDIT: To address Tryptich's comment - I did try this before posting :) As CMS said, an empty array is considered true. Try this:
if (c = [])
{
alert('empty array is true');
}
or even just this:
if ([])
{
alert('empty array is true');
}
I checked the spec before posting - I was somewhat surprised that an empty array is considered true, but it is...