Why _value is foo on second function call? It took me a while to find this bug.
function doSomething(value) {
console.log('should be:', value);
const _value = value || Math.random() > 0.5 ? 'foo' : 'bar';
console.log('actually is:', _value);
}
let values = ['foo', 'bar'];
const first = doSomething(values[0]);
const second = doSomething(values[1]);
To understand better I put a parenthes around the testing code:
(value || Math.random() > 0.5)
Since value is always defined (non null) the condition avaluates to true and assigns 'foo' to '_value'
Hope this explains it for you.
Because the expression
const _value = value || Math.random() > 0.5 ? 'foo' : 'bar';
is evaluated as:
const _value = (value || (Math.random() > 0.5)) ? 'foo' : 'bar';
The conditional operator has lower precedence than other operators in the expression.
value is a non-empty string, so it evaluates to true in boolean context. Thus, the condition evaluates to true, and the final result is always 'foo'.
Because:
> 'bar' == true
false
So:
const _value = value || Math.random() > 0.5 ? 'foo' : 'bar';
_value will be randomly assigned the value 'foo' or 'bar', because value is 'bar' which evaluates to false, so the second half of the or-expression || is evaluated and assigned to _value.
Try this.
const _value = value || (Math.random() > 0.5 ? 'foo' : 'bar');
Because JS in your code check such
`if(value || Math.random() > 0.5){
_value = 'foo';
}else{
_value ='bar'
}`
The construct const a = b || c is common Javascript shorthand. It means:
If b is not falsy assign it to a. Otherwise assign c to a.
It can also be written const a = b ? b : c; or
const a;
if (b) a = b;
else a = c;
A value is falsy generally speaking if it is empty or has the value zero.
Related
I have seen this syntax in node.jsv15.0.1: &&=, ||= and ??=.
But I don't know what it does. Does anyone know?
These are the new logical assignment operators. They're similar to the more familiar operators like *=, +=, etc.
someVar &&= someExpression is roughly equivalent to someVar = someVar && someExpression.
someVar ||= someExpression is roughly equivalent to someVar = someVar || someExpression.
someVar ??= someExpression is roughly equivalent to someVar = someVar ?? someExpression.
I say "roughly" because there's one difference - if the expression on the right-hand side isn't used, possible setters are not invoked. So it's a bit closer to:
someVar &&= someExpression is like
if (!someVar) {
someVar = someExpression;
}
and so on. (The fact that a setter isn't invoked is unlikely to have an effect on the script, but it's not impossible.) This is unlike the other traditional shorthand assignment operators which do unconditionally assign to the variable or property (and thus invoke setters). Here's a snippet to demonstrate:
const obj = {
_prop: 1,
set prop(newVal) {
this._prop = newVal;
},
get prop() {
return this._prop;
}
};
// Setter does not get invoked:
obj.prop ||= 5;
??, if you aren't familiar with it, is the nullish coalescing operator. It will evaluate to the right-hand side if the left-hand side is either null or undefined.
Those are called Logical Assignment Operators and there are three in total:
Logical AND assignment (&&=)
Logical OR assignment (||=)
Logical nullish assignment (??=)
Fundamentally they all do the same: The logical operators &&, ?? and || in front of the = as in x logical-operator= y can be rewritten as x logical-operator (x = y). Their only purpose is to replace more verbose code:
x &&= y does nothing if x is not truthy and changes x's value to y if x is truthy. It is the same as:
if (x) {
x = y
}
x ||= y does nothing if x is truthy and changes x's value to y if x is not truthy. It is the same as:
if (!x) {
x = y
}
x ??= y does nothing if x is not nullish and changes x's value to y if x is nullish. It is the same as:
if (x === null || x === undefined) {
x = y
}
Here are some examples to further your understanding of these:
const y = 'other value'
let def = 'initial' // truthy value
let zero = 0 // not truth value
let undef = undefined // nullish value
def &&= y // def = 'other value'
zero &&= y // zero = 0
undef &&= y // undef = 'undefined'
def ||= y // def = 'initial'
zero ||= y // zero = 'other value'
undef ||= y // undef = 'other value'
def ??= y // def = 'initial'
zero ??= y // zero = 0
undef ??= y // undef = 'other value'
a = a || b is equivalent to a ||= b => if a is true, a return but if a is false b return.
a = a && b is equivalent to a &&= b => if a is true, b return but if a is false a return.
a = a ?? b is equivalent to a ??= b => if a just is null or undefined, b return but if a is true a return.
note: null, undefined, "", 0, NaN are false
examples:
let a = -22
const b = false
a &&= b
console.log(a) // false
let a = 0
const b = 'hello'
a ||= b
console.log(a) // hello
let a = false
let b = true
a ??= b
console.log(a) // false
let a = null
let b = true
a ??= b
console.log(a) // true
If you do not understand, read it again!
I normally use ternary operators like:
let foo = str.match(/[*]/g) ? str.match(/[*]/g) : "none!";
Since using PHP, I've noticed the language has a lot of shorthand and for ternary operators, would use:
$foo = $view->test ?? "none";
I have not seen that in javascript (or documentation on it) but tried it like:
let str = "1234";
let foo1 = str.match(/[*]/g) ?? "none;
console.log(foo) // "none"
let str1 = "1*2*";
let foo1 = str1.match(/[*]/g) ?? "none;
console.log(foo1) // ['*','*']
and it seemingly works. Is this an acceptable way of using ternary operators when checking against the existence of an element?
I guess it's totally legit to use the nullish coalescing operator or ??.
See https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator for examples and some documentation on it.
Make sure to check browser compatibility though !
=======
There is also the logical OR || operator which can be used for similiar operations:
o1 = true || true // t || t returns true
o2 = false || true // f || t returns true
o3 = true || false // t || f returns true
o4 = false || (3 == 4) // f || f returns false
o5 = 'Cat' || 'Dog' // t || t returns "Cat"
o6 = false || 'Cat' // f || t returns "Cat"
o7 = 'Cat' || false // t || f returns "Cat"
o8 = '' || false // f || f returns false
o9 = false || '' // f || f returns ""
o10 = false || varObject // f || object returns varObject
Check out : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators for reference
How it's work for example;
let x;
console.log(x || 2); // 2
if
let x = 4;
console.log(x || 2); // 4
if
let x = 5;
let y = 7;
console.log( y || x || 2);
it's mean that console.log() write first value that is true ?
What you're seeing isn't related to console.log. It's called short circuiting.
When comparing values with ||, it will always return the first truthy value. If no truthy values are present, it will return the last value being compared.
let a = false || true;
let b = false || null || 'b';
let c = undefined || !a || 10;
let d = undefined || false || null; // no truthy values
console.log(a); // true
console.log(b); // 'b'
console.log(c); // 10
console.log(d); // null
let x = 5;
let y = 7;
console.log( y || x || 2); //return 7
expr1 || expr2 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.
Documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators
I have the following expression :
if(a && b === c) {//do something}
What would be the meaning of this condition if I consider that a,b, and c are strings ?
This is equal to if (a == true && b === c). (note that == is lose comparison. Eg. "foo" is loosely equal to true, however "" is not loosely equal to true, hence this says "if a is not an empty string, and b has the same content, and is the same type as c, then do something")).
Examples:
var a = 'foo';
var b = 'bar';
var c = 'bar';
Will be true because a is not falsy (a non empty string is truthy), and b is the same type and has the same content as c.
var a = '';
var b = 'bar';
var c = 'bar';
Will be false because a is falsy (an empty string is falsy).
var a = 'foo';
var b = 'rab';
var c = 'bar';
Will be false because b does not have the same content as c.
var a = 'foo';
var b = true;
var c = 1;
Will be false because b is not the same type as c (boolean vs number - with == this would be true, as true == 1).
Your expression expands to this:
if (a) {
if (b === c) {
// do something
}
}
It first checks that a is some truthy value. It then checks that b and c are of the same value and the same type. Read up on truthy and falsey values in JavaScript.
This means:
a is truthy
AND
b exactly equal to c (including type)
Here a is truthy means it is NOT ('undefined' or "" or 'null' or 0 or 'NaN' or 'FALSE')
if a have some value (not null and "") and b's value (string, case sensitive) is equal to c's value then your code
Consider the code snippet below from this AngularJS tutorial:
app.factory('Auth',
function ($firebaseSimpleLogin, FIREBASE_URL, $rootScope) {
var ref = new Firebase(FIREBASE_URL);
var auth = $firebaseSimpleLogin(ref);
var Auth = {
register: function (user) {
return auth.$createUser(user.email, user.password);
},
signedIn: function () {
return auth.user !== null;
},
logout: function () {
auth.$logout();
}
};
$rootScope.signedIn = function () {
return Auth.signedIn();
};
return Auth;
});
I understand the difference between != and !== is the first compares by reference and the second compares by value. Since the comparison here is to null, then why has the developer chosen to use !== instead of !=? Is my understanding correct that both would work here?
== / != operator only compares the value of the variables, not the type
=== / !== operator compares the type and the value of the variables
Some examples:
var varA = 5; // int
var varB = '5'; // string
var varC = 5; // int
if(varA == varB) // true (only value compared)
if(varA === varB) // false: because varB is of type string and varA of type int
if(varA == varC) // true
if(varA === varC) // true: because varA and varC are of the same type and have the same value
I often use "if(x != null)" to check if x is either null or undefined. It's safer than just saying "if(x)" since there are other falsey values besides null and undefined.
Here's an overview table, for your convenience: http://jsfiddle.net/QQcVw/1/
0 "" false null undefined
0 Y Y Y n n
"" Y Y Y n n
false Y Y Y n n
null n n n Y Y
undefined n n n Y Y
As you can see, == considers equal three empty "values" (0, "" and false) and two "non-values" (null and undefined). See javascript standard for the exact algorithm.
In most cases, it's a good idea to avoid == and always stick to ===.