Why is the Javascript operator "&&" so weird? - javascript

a = 1;
b = "1";
if (a == b && a = 1) {
console.log("a==b");
}
The Javascript code above will result in an error in the if statement in Google Chrome 26.0.1410.43:
Uncaught ReferenceError: Invalid left-hand side in assignment
I think this is because the variable a in the second part of the statement &&, a=1 cannot be assigned. However, when I try the code below, I'm totally confused!
a = 1;
b = "1";
if (a = 1 && a == b) {
console.log("a==b");
}
Why is the one statement right but the other statement wrong?

= has lower operator precendence than both && and ==, which means that your first assignment turns into
if ((a == b && a) = 1) {
Since you can't assign to an expression in this way, this will give you an error.

The second version is parsed as a = (1 && a == b); that is, the result of the expression 1 && a == b is assigned to a.
The first version does not work because the lefthand side of the assignment is not parsed as you expected. It parses the expression as if you're trying to assign a value to everything on the righthand side--(a == b && a) = 1.
This is all based on the precedence of the various operators. The problem here stems from the fact that = has a lower precedence than the other operators.

Because the order of operations is not what you expect. a == b && a = 1 is equivalent to (a == b && a) = 1 which is equivalent to false = 1.
If you really want to do the assignment, you need to use parentheses around it: a == b && (a = 1).

In if (a = 1 && a == b),
The operations to be first performed is 1 && a == b. 1 && the result of a == b is performed. The result of this && operation is assigned to a.

Related

Is Variable Initialization statement an expression in JavaScript?

The following works:
let x = 1 && console.log("true"); (-- logs true)
let y = 0 && console.log("true"); (-- logs nothing)
The above shows that the statement before && operator is acting like an expression.
Then I tried this:
console.log(let m = 5); // Error
What is going on here? If that's an expression then why it didn't work in this case and if it's not an expression then why it worked in the first two cases?
The following works -
let x = 1 && console.log("true"); (-- logs true)
let y = 0 && console.log("true"); (-- logs nothing)
The above shows that the statement before && operator is acting like an expression
This is where you are mistaken. The && operator is used to join expressions, not statements (even though it has control flow effects). This parses as follows:
let x = (1 && console.log("true")); (-- logs true)
let y = (0 && console.log("true")); (-- logs nothing)
console.log is acting as an expression here, not let .... Function calls always return a value (which may be undefined). If you logged x and y, you'd see that x === undefined (result of 1 && undefined) and y === 0 (result of 0 && <not evaluated>).
It is probably confusing you here that && short-circuits: In the first expression, the first operand of && is 1 (truthy), so the second operand - the expression which is a call to console.log - has to be evaluated; in the second expression, the first operand of && is the falsy 0, so && short-circuits to 0, not evaluating (not calling) console.log("true").
let statements are statements and not expressions, which is why you get a syntax error in your second example.

Does EcmaScript have "reverse if notation"?

The normal way to write an if-statement is
if (a == b) {a=1}
but in eg. Perl it is possible to write the same as
a=1 if (a == b)
Question
Is a similar syntax possible with EcmaScript?
There is not a specific statement to do that. You still have several options though
if (a == b) {
a = 1
}
if (a == b) a = 1 // No parenthesis
a == b ? a = 1 : null // Using ternary operator
a = a == b ? 1 : a // Using ternary operator

JavaScript Logical OR invalid assignment

I'm trying to understand how JavaScript's logical OR operator works and I am trying to recreate a code I read in a book but with my own twist to it but I keep getting a reference error when I try to run the code.
function add(a,b) {
b || b = 1;
return a+b;
}
My understanding is that if the left operand is false then the right operand is evaluated then the right operand's value is returned or used. With the code above, what I am trying to do is when the function is invoked and the second parameter is omitted, it would use a default value of 1 as the second value to the equation, but I keep getting a reference error that states invalid left hand assignment.
Probably you wanna achieve this:
b = b || 1;
Try b || (b = 1) instead. That's also exactly what CoffeeScript generates for its ||= operator.
The problem is with operator precedence. Assignment = has lower precedence than boolean or ||, therefore this
b || b = 1
is interpreted as
(b || b) = 1
which is invalid, because you cannot assign to an expression. To achieve what you want you have to tell JS you want || first and then =:
b || (b = 1)
but a more common way to express this would be
b = b || 1
In the context of your function this might not work as expected, since 0 is a valid integer value, and your code will treat it as false and substitute it with 1. So, the correct, although more verbose, way to write your function is
function add(a, b) {
b = (typeof b == "undefined") ? 1 : b;
return a + b;
}

Using and (&&) and or (||) together in the same condition in JavaScript

I'm wondering how to combine and (&&) with or (||) in JavaScript.
I want to check if either both a and b equal 1 or if both c and d equal 1.
I've tried this:
if (a == 1 && b == 1 || c == 1 && d == 1)
{
//Do something
}
But it doesn't work.
How can I write this condition correctly?
&& precedes ||. == precedes both of them.
From your minimal example I don't see, why it doesn't achieve your desired effect. What kind of value types do a–d have? JavaScript might have some non-obvious type coercion going on. Maybe try comparing with === or convert to numbers explicitly.
Side note: many lint tools for C-like languages recommend to throw in parentheses for readability when mixing logical operators.
Operator Precedence can be overridden by placing the expression between parenthesis.
if ((+a == 1 && +b == 1) || (+c == 1 && +d == 1)) // Use brackets to group them
{
// your code
}
This will prevent you from such cases like if(0&&0 || 1&&1) .
Well now that I've finished telling everybody else (except David) why their answers are wrong, let me give them the same chance to hassle me.
Your existing code as shown should already do what you seem to be describing. But is it possible that when you say:
"I want to check if either both a and b equals 1 or if both c and d equals 1."
...your use of the word "either" mean that you want to check if one and only one of the following conditions is true:
both a and b are 1, but c and d are not both 1
both c and d are 1, but a and b are not both 1
That is, you want one pair of variables to be 1, but you don't want all four variables to be 1 at the same time?
If so, that is an exclusive OR operation, which in JS is the ^ operator:
if ((a == 1 && b == 1) ^ (c == 1 && d == 1)) {
Note that unlike with a logical OR || operator, you have to add parentheses around the AND && parts of the expression because ^ has higher precendence. (^ is actually a bitwise operator, but it will work for you here since the operands you'd be using with it are all booleans.)
place some extra brackets to differentiate the and n or conditions
if ((a == 1 && b == 1) || (c == 1 && d == 1))

What is this JS syntax? Assignment in expression? (x != null && (y = x))

I'm working with this JS plugin, and I've encountered some syntax I've never seen before. I understand what it's doing, but I'm not sure why it works.
Here's an example of one instance of it:
settings.maxId != null && (params.max_id = settings.maxId);
Is this just taking advantage of conditionals and the single = ? Is this common syntax for JS?
In JavaScript the = operator is an expression and evaluates the assigned value. Because it is an expression it can be used anywhere an expression is allowed even though it causes a side-effect.
Thus:
settings.maxId != null && (params.max_id = settings.maxId)
Means: If settings.maxId is not null then (and only then, since && is short circuiting) evaluate the right-expression (params.max_id = settings.maxId) which in turn causes the value of settings.maxId to be assigned to params.max_id.
This is much more clearly written as:
if (settings.maxId != null) {
params.max_id = settings.maxId
}
Happy coding.
The && operator is known as "boolean AND". Typically, you'd see it in an if statement:
if (x == true && y == false) {
but that's not a restriction. You may use it in any valid expression to "combine" the boolean values of its operands into a single boolean result, according to the logical "AND" operation:
var z = (x == true && y == false);
// z is now true or false, accordingly
One of the lovely things about && is that it "short circuits". In false && true, because the first operand is false the entire expression may only evaluate to false, so the second operand is not even evaluated.
Let's check that again:
var z = (false && foo());
// z is now false
In this statement, the function foo is never even called! It doesn't have to be, for the program to know that z will be false.
This is more than an optimisation — you can rely on it.
Some silly people use this technique to rewrite conditional statements:
if (x == 0) {
foo();
}
into hard-to-read single expressions:
(x == 0) && foo();
Now, consider that assignment can be an expression just like a function call:
var a = (b = c);
Or:
var a = (b = foo());
And add in a conditional via the above technique:
var a = ((x == 0) && (b = foo()));
Now the entire expression b = foo() won't be evaluated at all if x is not 0, because of short circuiting.
We don't even need to do anything with the result of the && operation, and if we don't store it to a you're left with just:
(x == 0) && (b = foo());
which is a statement that'll assign b to the value of foo() only if x is 0.
Avoid it. It's hard to read. Just use an if statement.
this statement will assign params.max_id = settings.maxId only if settings.maxId != null due to the fact that && is a short-circuit logic operator
this behaviour is due to the fact that javascript will evaluate the condition until it's necessary. thus, if first condition is false and the second is in AND there's no need to check further

Categories