JavaScript’s Gotchas, also known as “WTF JS

RMAG news

1. Arrays and Equality

[] == ![]; // -> true
// Explanation: Arrays are truthy, so ![] is false, which coerces to 0. [] coerces to 0, so 0 == 0 is true.

true == []; // -> false
true == ![]; // -> false
// Explanation: true converts to 1 and [] converts to 0. 1 != 0.

false == []; // -> true
false == ![]; // -> true
// Explanation: false and [] both convert to 0. 0 == 0.

2. Type Coercion Oddities

!!false == !!true; // -> true
// Explanation: Both strings are truthy, so !! converts them to true.

b + a + +a + a; // -> ‘baNaNa’
// Explanation: +”a” converts ‘a’ to NaN, so it becomes “ba” + NaN + “a” which is ‘baNaNa’.

NaN === NaN; // -> false
// Explanation: NaN is not equal to anything, including itself.

3. Object Comparison

Object.is(NaN, NaN); // -> true
NaN === NaN; // -> false
// Explanation: Object.is and === have different behaviors for NaN.

Object.is(0, 0); // -> false
0 === 0; // -> true
// Explanation: -0 and 0 are considered equal with === but not with Object.is.

4. Fun with Syntax

[1, 2, 3] + [4, 5, 6]; // -> ‘1,2,34,5,6’
// Explanation: Arrays are converted to strings and concatenated.

let a = [, , ,];
a.length; // -> 3
// Explanation: Trailing commas create empty slots, affecting array length.

5. Number Coercion and Parsing

parseInt(null, 24); // -> 23
// Explanation: null is converted to a string and then parsed according to the specified radix.

0.1 + 0.2; // -> 0.30000000000000004
// Explanation: Floating-point arithmetic can produce imprecise results.

true + true; // -> 2
(true + true) * true true; // -> 1
// Explanation: Booleans are coerced to numbers in arithmetic operations.

Number(); // -> 0
Number(undefined); // -> NaN
// Explanation: Number without arguments returns 0, with undefined returns NaN.

6. Unexpected Typeof and Instanceof

typeof NaN; // -> ‘number’
// Explanation: Despite its name, NaN is of type ‘number’.

typeof null; // -> ‘object’
// Explanation: Null is considered an object in JavaScript, although it is a primitive value.

7. Miscellaneous

{} + []; // -> 0
[] + {}; // -> ‘[object Object]’
// Explanation: The order of operations and type coercion produce different results.

[10, 1, 3].sort(); // -> [1, 10, 3]
// Explanation: Default sorting converts elements to strings, sorting them lexicographically.

let f = () => {};
f(); // -> undefined
// Explanation: Arrow function with empty block returns undefined.

let f = function() { return arguments; };
f(a); // -> { ‘0’: ‘a’ }
// Explanation: Regular function captures arguments.

let f = () => arguments;
f(a); // -> ReferenceError: arguments is not defined
// Explanation: Arrow function does not capture arguments.

(() => {
try {
return 2;
} finally {
return 3;
}
})(); // -> 3
// Explanation: finally block overrides the return statement.

new class F extends (String, Array) {}(); // -> F []
// Explanation: Extends clause uses the last argument, so class extends Array.

let x, { x: y = 1 } = { x };
y; // -> 1
// Explanation: Destructuring with default value when x is undefined.

[…[…]].length; // -> 3
// Explanation: Spreading a string spreads its characters into an array.

foo: {
console.log(first);
break foo;
console.log(second);
}
// Explanation: Labeled block with break statement.

typeof new class { class() {} }(); // -> ‘object’
// Explanation: Keyword can be used as method name.

📚 Other resources

qit.tools – JavaScript’s Gotchas (WTF JS): Unexpected Behaviors

Please follow and like us:
Pin Share