10 Amazing JavaScript Tricks That Will Surprise You

10 Mind-Blowing JavaScript Facts Every Developer Should Know

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); // JavaScript

3. Objects Can Have Computed Property Names

const key = "name";

const user = {
  [key]: "Alice"
};

console.log(user.name); // Alice

4. Destructuring with Default Values

const user = {
  name: "John"
};

const { name, age = 25 } = user;

console.log(name); // John
console.log(age);  // 25

5. Optional Chaining (?.)

Avoids errors when accessing nested properties.

const user = {};

console.log(user.address?.city); // undefined

Instead 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()); // 3

The 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.


Thank You!