DEV Community

Cover image for Decoding the Weird Parts of JavaScript Every Developer Should Know
Vishal Kinikar
Vishal Kinikar

Posted on

Decoding the Weird Parts of JavaScript Every Developer Should Know

JavaScript, the language we love (or love to hate), is filled with unique behaviors and quirks that make it both powerful and perplexing. While these "weird parts" can confuse beginners, mastering them is essential to becoming a proficient developer. Let’s dive into some fascinating JavaScript oddities that every developer should know.


1. Coercion: JavaScript's Secret Magician

JavaScript tries to be helpful by converting values between types, but this "helpfulness" can lead to surprising results.

Example: Unexpected Math

console.log('5' - 3);  // 2
console.log('5' + 3);  // '53'
Enter fullscreen mode Exit fullscreen mode
  • Subtraction: JavaScript converts '5' to a number before subtracting.
  • Addition: When a string is involved, JavaScript concatenates instead of adding.

Why It Matters

  • This implicit conversion (type coercion) can introduce bugs if you're not careful.
  • Always use explicit conversions with Number(), String(), or Boolean() to avoid surprises.

2. The Mystery of this

The behavior of this in JavaScript is often confusing because it changes depending on how a function is called.

Example: Different Contexts

function showThis() {
  console.log(this);
}

showThis();  // Window or undefined in strict mode

const obj = { method: showThis };
obj.method();  // obj

const boundFunc = showThis.bind(obj);
boundFunc();  // obj
Enter fullscreen mode Exit fullscreen mode

Why It Matters

  • this is not set at the time of declaration; it depends on the call site.
  • Arrow functions don't have their own this, making them perfect for preserving lexical context.

3. The Event Loop: Asynchronous JavaScript Demystified

JavaScript is single-threaded but can handle asynchronous tasks through the event loop.

Example: What Runs First?

console.log('Start');

setTimeout(() => console.log('Timeout'), 0);

Promise.resolve().then(() => console.log('Promise'));

console.log('End');
Enter fullscreen mode Exit fullscreen mode

Output

Start
End
Promise
Timeout
Enter fullscreen mode Exit fullscreen mode
  • Synchronous code runs first.
  • Promises (microtasks) are prioritized over setTimeout (macrotasks).

Why It Matters

Understanding the event loop is key to writing performant asynchronous code.


4. Closure: The Function That Remembers

A closure is when a function "remembers" its lexical scope even after the outer function has returned.

Example: Private Variables

function counter() {
  let count = 0;
  return function () {
    count++;
    console.log(count);
  };
}

const increment = counter();
increment();  // 1
increment();  // 2
Enter fullscreen mode Exit fullscreen mode

Why It Matters

Closures allow you to create private variables and maintain state across function calls.


5. Prototypes: The Backbone of JavaScript

JavaScript uses prototype-based inheritance, meaning objects can inherit properties and methods from other objects.

Example: Custom Methods

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function () {
  console.log(`Hello, my name is ${this.name}`);
};

const alice = new Person('Alice');
alice.greet();  // Hello, my name is Alice
Enter fullscreen mode Exit fullscreen mode

Why It Matters

Prototypes enable you to share methods across instances efficiently.


6. Equality Checks: == vs ===

JavaScript provides both loose equality (==) and strict equality (===), and they behave differently.

Example: The Weird Case of Null and Undefined

console.log(null == undefined);  // true
console.log(null === undefined); // false
Enter fullscreen mode Exit fullscreen mode
  • == performs type conversion, so null is loosely equal to undefined.
  • === checks for both type and value equality.

Why It Matters

Always use === unless you explicitly need type conversion.
Avoid comparing non-primitive values directly ({} !== {}).


7. Immutability and Reference Types

JavaScript treats objects and arrays as reference types, meaning changes to a reference affect the original.

Example: Copying Pitfalls

const original = { key: 'value' };
const copy = original;
copy.key = 'newValue';

console.log(original.key);  // 'newValue'
Enter fullscreen mode Exit fullscreen mode

Why It Matters

  • Use Object.assign() or the spread operator ({ ...original }) to create shallow copies.
  • For deep copies, consider libraries like Lodash or structuredClone.

8. NaN: Not As Simple As It Seems

NaN stands for "Not a Number," but its behavior is anything but straightforward.

Example: Comparing NaN

console.log(NaN == NaN);  // false
console.log(Object.is(NaN, NaN));  // true
Enter fullscreen mode Exit fullscreen mode

Why It Matters

Use Object.is when you need strict equivalence for special cases like NaN.


9. Hoisting: What’s Declared First?

Hoisting moves variable and function declarations to the top of their scope.

Example: Hoisting Variables

console.log(x);  // undefined
var x = 10;

hoistMe();
function hoistMe() {
  console.log('Hoisted!');
}
Enter fullscreen mode Exit fullscreen mode
  • var declarations are hoisted but initialized as undefined.
  • Function declarations are fully hoisted.

Why It Matters

Use let and const to avoid variable hoisting confusion.


10. Weird Defaults: Default Parameters

Default parameters make functions more flexible but can behave strangely when combined with undefined.

Example: Defaults and Arguments

function greet(name = 'Guest') {
  console.log(`Hello, ${name}`);
}

greet();          // Hello, Guest
greet(undefined); // Hello, Guest
greet(null);      // Hello, null
Enter fullscreen mode Exit fullscreen mode

Why It Matters

Default parameters are only applied if the argument is undefined, not null.


Conclusion: Embrace the Weirdness

JavaScript's quirks make it both frustrating and fun. Understanding these behaviors will not only make you a better developer but also help you appreciate the language's flexibility and design choices.

Which of these quirks have you encountered, and how did you tackle them? Share your thoughts in the comments below!

Top comments (0)