A list of questions based on uncommon or tricky concepts in Javascript.
Number(undefined)
NaN
Number(" 123 ")
Number("12 3")
123, NaN (only whitespace from the start and end are removed)
Boolean(" ")
Boolean("0")
true, true
Only values that are intuitively “empty”, like 0, "", null, undefined, and NaN, become false.
typeof null
object
That’s an officially recognized error in typeof behavior, coming from the early days of JavaScript and kept for compatibility.
Definitely, null is not an object. It is a special value with a separate type of its own.
2 ** 2
2² = 4
2 + 2 + '1'
'1' + 2 + 2
4 + '1' >> '41'
'12' + 2 >> '122'
+true
+""
+"2" + +"3"
1, 0, 5
The plus + exists in two forms: the binary and the unary form.
The unary plus doesn’t do anything to numbers. But if the operand is not a number, the unary plus converts it into a number.
let a = 1;
let b = 2;
let c = 3 - (a = b + 1);
// Good to understand how it works. Please don’t write the code like that.
0
All operators in JavaScript return a value. That’s obvious for + and -, but also true for =
The call x = value writes the value into x and then returns it.
let a = (1 + 2, 3 + 4);
a = 7
The comma operator allows us to evaluate several expressions, dividing them with a comma ,. Each of them is evaluated but only the result of the last one is returned.
Why do we need an operator that throws away everything except the last expression?
Sometimes, people use it in more complex constructs to put several actions in one line.
For example:
// three operations in one line
for (a = 1, b = 3, c = a * b; a < 10; a++) {
...
}
// doesn't improve code readability so we should think well before using this.
let y = "5";
let x = y++; // number or string 5?
number 5
JavaScript first coerces the string to a number then assigns the value to the variable x and then increments the value.
let a = NaN;
let b = NaN;
a === b;
a == b;
false, false
NaN is the only value in JavaScript that is not equal to itself. So we can check for a NaN value by checking if the value is equal to itself. According to IEEE standard NaN is not equal to NaN.
isNaN("this is a string not a NaN value");
Number.isNaN("this is a string not a NaN value");
true, false
isNaN tries to coerce the value into a Number before checking if it's a NaN value. This issue has been fixed in Number.isNaN().
let negativeZero = -0;
negativeZero.toString();
negativeZero === 0;
negativeZero < 0;
negativeZero > 0;
Object.is(negativeZero, -0)
Object.is(negativeZero, 0)
"0", true, false, false
When we try to use these operations we get some unexpected behaviour because language developers decided negative zero isn't needed.
true, false This was fixed in Object.is() method.
Use case of -0: To show direction when something is stationary
let string = 'orange';
function changeToApple(string) {
string = 'apple';
}
changeToApple(string);
console.log(string); // ??
const promise = new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log("timerStart");
resolve("success");
console.log("timerEnd");
}, 0);
console.log(2);
});
promise.then(console.log);
console.log(3);
let fruit = prompt("Which fruit to buy?", "apple");
let bag = {
[fruit]: 5,
};
let obj = {
for: 1,
let: 2,
return: 3
};
console.log( obj.for + obj.let + obj.return );
let obj = {
test: undefined
};
if(obj.test){
console.log("hi);
}
if("test" in obj){ // returns true console.log("hi"); }
let codes = {
"49": "Germany",
"41": "Switzerland",
"44": "Great Britain",
// ..,
"1": "USA"
};
for (let code in codes) {
console.log(code);
}
let a = {};
let b = a;
log( a == b );
log( a === b );
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("Jack");
function User() {
if(new.target){
console.log("Hi");
}
}
User();
new User();
function BigUser() {
this.name = "John";
return { name: "Godzilla" };
}
function SmallUser() {
this.name = "John";
return "Rick";
}
console.log( new BigUser().name );
console.log( new SmallUser().name );
If return is called with an object, then the object is returned instead of this If return is called with a primitive, it’s ignored.
function User(){
this.name = "Admin"
}
let user = new User;
let ladder = {
step: 0,
up() {
this.step++;
},
down() {
this.step--;
},
showStep: function() {
alert( this.step );
}
};
// ladder.up().up().down().showStep(); // 1
function A() { ... }
function B() { ... }
let a = new A;
let b = new B;
alert( a == b ); // true
If a function returns an object then new returns it instead of this.
So they can, for instance, return the same externally defined object obj
let obj = {};
function A() { return obj; }
function B() { return obj; }
alert( new A() == new B() ); // true
let user = {
address: null
};
log( user?.name?.first );
log( user?.address?.street )
The optional chaining ?. stops the evaluation if the value before ?. is undefined or null and returns undefined
log(user?.address);
let userAdmin = {
admin() {
alert("I am admin");
}
};
let userGuest = {};
log(userAdmin.admin?.());
log(userGuest.admin?.());
The optional chaining ?. is not an operator, but a special syntax construct, that also works with functions and square brackets. ?.(), ?.[]
delete user?.name;
user?.name = "John";
We can use ?. for safe reading and deleting, but not writing
let numbers = {
0: 0
}
numbers.1 = 1;
the numbers.1 = 1;
is invalid
let numbers = {
0: 0
}
log(numbers."0");
log(numbers[0]);
alert( 1 || 0 );
alert( null || 1 );
alert( null || 0 || 1 );
alert( undefined || null || 0 )
|| returns the first truthy value (without any conversion) or the last one if no truthy value is found
alert( 1 && 0 );
alert( 1 && 5 );
alert( null && 5 );
alert( 0 && "no matter what" );
AND returns the first falsy value(without any conversion) or the last value if none were found
alert( !!"non-empty string" );
alert( !!null );
double NOT !! is sometimes used for converting a value to boolean type. The first NOT converts the value to boolean and returns the inverse, and the second NOT inverses it again. In the end, we have a plain value-to-boolean conversion.
NaN ** 0
let n = 2;
n *= 3 + 5