10 Amazing JavaScript Tricks That Will Surprise You
JavaScript has a lot of surprising and interesting behaviours. Here are a few fun ones
1. [] == ![] is true
console.log([] == ![]); // true
Why?
- ![] becomes false (because an empty array is truthy).
- [] is converted to an empty string "".
- false is converted to 0.
- "" is also converted to 0.
- So it's 0 == 0.
2. Functions are Objects
You can attach properties to functions.
function greet() {
console.log("Hello");
}
greet.language = "JavaScript";
console.log(greet.language); // JavaScript3. Objects Can Have Computed Property Names
const key = "name";
const user = {
[key]: "Alice"
};
console.log(user.name); // Alice4. Destructuring with Default Values
const user = {
name: "John"
};
const { name, age = 25 } = user;
console.log(name); // John
console.log(age); // 255. Optional Chaining (?.)
Avoids errors when accessing nested properties.
const user = {};
console.log(user.address?.city); // undefinedInstead of:
// TypeError console.log(user.address.city);
6. Closures (One of JavaScript's Superpowers)
function counter() {
let count = 0;
return function () {
count++;
return count;
};
}
const c = counter();
console.log(c()); // 1
console.log(c()); // 2
console.log(c()); // 3The inner function remembers count even after counter() has finished.
7. Everything is Single-Threaded, But Asynchronous
console.log("Start");
setTimeout(() => {
console.log("Timeout");
}, 0);
console.log("End");
Output:
Start
End
Timeout
Even with a delay of 0, the callback runs after the current call stack is empty.
8. NaN is Not Equal to Itself
console.log(NaN === NaN); // false
To check for NaN:
console.log(Number.isNaN(NaN)); // true
9. typeof null
console.log(typeof null); // "object"
This is a historical bug in JavaScript that remains for backward compatibility.
10. this Depends on How a Function is Called
const person = {
name: "Sam",
greet() {
console.log(this.name);
}
};
person.greet(); // Sam
const fn = person.greet;
fn(); // undefined (in strict mode)
this is determined by the call site, not where the function is defined.
Bonus: A JavaScript Puzzle
What will this print?
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
Answer:
3
3
3
Because var is function-scoped, all callbacks share the same i, whose final value is 3.
Using let instead:for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
Output:
0
1
2
because let creates a new binding for each iteration. These quirks and features are part of what makes JavaScript both powerful and occasionally surprising.
I hope this helped you learn something new.
