Exploring the quirks and features of JavaScript that can lead to unexpected behavior, including type coercion and scope issues.
var
and let
var x = 1;
if (true) {
var x = 2; // Same variable
console.log(x); // 2
}
let y = 1;
if (true) {
let y = 2; // Different variable
console.log(y); // 2
}
console.log(x); // 2
console.log(y); // 1
In JavaScript, var
is function-scoped or globally scoped, meaning it can be re-declared and updated within the same scope. In contrast, let
is block-scoped, meaning it is confined to the block in which it is defined. This can lead to confusion when using var
inside blocks like if
statements.
const
isn’t actually constant valueconst obj = { name: 'John' };
obj.name = 'Jane'; // This is allowed
This is because const
only prevents reassignment of the variable itself, not the properties of the object it references.
NaN
a"b" + "a" + +"a" + "a"; // "baNaNa"
This is a classic JavaScript quirk where the unary +
operator attempts to convert the string 'a'
to a number, resulting in NaN
. The expression evaluates to 'b' + 'a' + NaN + 'a'
, which concatenates to 'baNaNa'
.
parseInt
and parseFloat
quirksparseInt(0.0000005) // 5
parseInt
and parseFloat
can behave unexpectedly with very small numbers. In this case, parseInt(0.0000005)
returns 5
because it ignores the leading zeros and interprets the number as 5
.
const numbers = [10, 1, 21, 2];
numbers.sort(); // [1, 10, 2, 21]
When sorting an array of numbers, JavaScript’s Array.prototype.sort()
method sorts them as strings by default. This can lead to unexpected results, as it compares the string representations of the numbers rather than their numeric values. To sort numerically, you should provide a comparison function:
Number.MIN_VALUE
is greater than 0
> Number.MIN_VALUE
5e-324
> Number.MIN_VALUE > 0
true
Number.MIN_VALUE
represents the smallest positive number that can be represented in JavaScript, which is approximately 5e-324
. It is greater than 0
, but it is not the smallest possible value; rather, it is the smallest positive non-zero value.
NaN
is a numberconsole.log(typeof NaN); // 'number'
console.log(NaN === NaN); // false
console.log(isNaN(NaN)); // true
NaN
stands for “Not a Number” and is a special value in JavaScript that represents an undefined or unrepresentable value in numerical calculations. It is of type number
, but it is not equal to itself, which is why NaN === NaN
returns false
. The function isNaN()
can be used to check if a value is NaN
.
0.1 + 0.2; // 0.30000000000000004
0.1 + 0.2 === 0.3; // false
Floating point arithmetic in JavaScript can lead to precision issues due to the way numbers are represented in binary. The result of 0.1 + 0.2
is not exactly 0.3
, but rather 0.30000000000000004
, which can cause unexpected behavior in comparisons.
[1, 2, 3].map(parseInt); // [1, NaN, NaN]
The parseInt
function can behave unexpectedly when used with Array.prototype.map()
. The second argument of parseInt
is the radix (base) for the conversion, and when map
calls parseInt
, it passes the index of the element as the second argument. This results in only the first element being parsed correctly, while the others return NaN
.
Infinity
console.log(1 / 0); // Infinity
console.log(Infinity + 1); // Infinity
console.log(Infinity - Infinity); // NaN
console.log(Infinity * 2); // Infinity
console.log(Infinity / 2); // Infinity
console.log(Infinity * 0); // NaN
console.log(Infinity === Infinity); // true
console.log(Infinity === 1 / 0); // true
console.log(Infinity > 1000); // true
console.log(Infinity < -1000); // false
console.log(Infinity.toString()); // 'Infinity'
console.log(typeof Infinity); // 'number'
Infinity is a special numeric value in JavaScript that represents an unbounded value. It can result from dividing a positive number by zero or from certain mathematical operations that exceed the maximum representable number in JavaScript. Infinity behaves like a number in most operations, but it has some unique properties, such as being greater than any finite number and being equal to itself.
this
keywordfunction test() {
console.log(this);
}
test(); // In non-strict mode, this refers to the global object (window in browsers)
test.call({ name: 'Alice' }); // { name: 'Alice' } (this refers to the object passed to call)
The this
keyword in JavaScript can be confusing because its value depends on how a function is called. In non-strict mode, if a function is called without an explicit context (like test()
), this
refers to the global object (e.g., window
in browsers). However, when using methods like call
, apply
, or bind
, you can explicitly set the value of this
.
function example() {
console.log(x); // undefined (due to hoisting)
var x = 5;
console.log(x); // 5
}
example();
In JavaScript, variable declarations using var
are hoisted to the top of their containing function or global scope. This means that the variable is accessible before its declaration, but it will be undefined
until the line where it is assigned a value. In contrast, variables declared with let
and const
are not hoisted in the same way and will throw a ReferenceError
if accessed before their declaration.
console.log(Boolean(0)); // false
console.log(Boolean('')); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean('Hello')); // true
console.log(Boolean(42)); // true
console.log(Boolean([])); // true (empty array is truthy)
console.log(Boolean({})); // true (empty object is truthy)
JavaScript has a set of truthy and falsy values that can lead to unexpected behavior in conditional statements. Falsy values include 0
, ''
(empty string), null
, undefined
, and NaN
. All other values, including non-empty strings, non-zero numbers, objects, and arrays, are considered truthy.
In comparison, Python has a more straightforward approach to truthy and falsy values, where None
, 0
, ''
, and empty collections (like []
and {}
) are considered falsy, while all other values are truthy.
JavaScript performs type coercion in many situations, which can lead to unexpected results. For example:
console.log('2' + 3); // '23' (string + number => string)
console.log('2' - 3); // -1 (string - number => number)
console.log(2 + true); // 3 (number + boolean => number)
console.log(2 + null); // 2 (number + null => number)
console.log(2 + undefined); // NaN (number + undefined => NaN)
console.log('2' * '3'); // 6 (string * string => number)
console.log('2' * []); // 2 (string * array => number)
console.log([] + {}); // '[object Object]' (array + object => string)
null
and undefined
console.log(typeof null); // 'object' (this is a historical bug in JavaScript)
console.log(typeof undefined); // 'undefined' (this is correct)
console.log(null == undefined); // true (they are loosely equal)
console.log(null === undefined); // false (they are strictly not equal)
In JavaScript, null
is an object type, which is a historical quirk. It can lead to confusion when checking types.