Six Things You May Not Know About JavaScript

JavaScript is an essential part of modern web development and powers interactive features on almost every website. It’s known for its flexibility and has come a long way since its early days as a simple scripting language. Even seasoned developers sometimes encounter unexpected quirks or features in JavaScript that can catch them off guard. Here are six things you may not know about JavaScript—each offering an insight into the language’s complexities, quirks, and hidden power.

1. JavaScript Is Single-Threaded… But Can Still Handle Asynchronous Operations

JavaScript is inherently single-threaded, meaning it can only execute one task at a time. However, it manages asynchronous operations effectively with the help of the event loop, callbacks, promises, and async/await. When asynchronous code (like fetching data from a server) is executed, JavaScript offloads it, freeing up the main thread to continue running other code.

For example, using setTimeout() to delay a function doesn’t actually pause the main thread; instead, it’s sent to a queue to be handled by the event loop once the stack is clear. The single-threaded nature of JavaScript often surprises those new to asynchronous programming.

2. The “this” Keyword Isn’t Always What You Think

The this keyword in JavaScript refers to different things depending on the context. This can lead to confusing behavior, especially for developers used to other languages. Here’s a brief breakdown of how this behaves in different scenarios:

  • In the global scope: this refers to the global object (like window in browsers).
  • Inside functions: this can depend on how the function is called. Regular functions may point to the global scope, while arrow functions don’t have their own this and instead inherit it from their lexical scope.
  • Inside objects: When a method is invoked within an object, this points to the object itself.

This quirky behavior is why frameworks like React often use arrow functions in class components to avoid unpredictable this values.

3. JavaScript Has Type Coercion—and It’s Not Always Logical

JavaScript’s loose typing system can lead to unexpected results, especially with type coercion, where values are implicitly converted to match the expected type. Here are some curious outcomes:

console.log(1 + "2");   // "12" (number + string becomes a concatenated string)
console.log(1 + 2 + "3"); // "33" (numbers are added first, then concatenated)
console.log("10" - 1);   // 9 (string is coerced to number)
console.log(false == 0); // true (false coerced to 0)
console.log(true + true); // 2 (booleans coerced to numbers)

This is why === (strict equality) is generally preferred over == (loose equality) in JavaScript. The strict equality operator compares both type and value, while == allows for type coercion.

4. JavaScript Supports Closures

Closures are one of JavaScript’s most powerful and unique features. A closure occurs when a function retains access to its lexical scope, even when it’s executed outside of its original scope. This enables you to create functions with “private” variables.

function createCounter() {
    let count = 0;
    return function () {
        count += 1;
        return count;
    };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2

In this example, counter retains access to count even after createCounter() has finished executing. Closures are commonly used for data encapsulation and creating function factories.

5. JavaScript Arrays Aren’t Always Arrays

JavaScript arrays are specialized objects, with array indices acting as property names and the array itself inheriting methods from Array.prototype. Since arrays are objects, they can contain additional non-numeric properties.

let arr = [1, 2, 3];
arr.customProperty = "Hello, World!";
console.log(arr); // [1, 2, 3, customProperty: "Hello, World!"]

Additionally, arrays in JavaScript are not guaranteed to be contiguous, which allows for “holes” in an array. This means that you can create an array with gaps and access undefined values:

let sparseArray = [1, , 3];
console.log(sparseArray[1]); // undefined
console.log(sparseArray.length); // 3

These peculiarities make JavaScript arrays both flexible and sometimes unintuitive, so it’s essential to understand how they behave under the hood.

6. JavaScript Hoisting Affects Variable and Function Declarations

JavaScript performs hoisting, which moves variable and function declarations to the top of their scope during the compile phase. This means you can use variables and functions before declaring them, though the outcomes differ between var, let, and const.

console.log(myVar); // undefined (hoisted but not initialized)
var myVar = "Hello";

console.log(myLet); // ReferenceError (not hoisted)
let myLet = "World";

For functions, hoisting can result in strange behavior as well:

sayHello(); // Works fine due to hoisting
function sayHello() {
    console.log("Hello, world!");
}

Hoisting can cause bugs if you’re not careful, especially when using var, which can result in “undefined” values due to hoisting without initialization. Understanding how hoisting works will help you avoid common pitfalls in JavaScript code.


JavaScript is full of fascinating quirks that can surprise even experienced developers. The language’s flexibility offers developers powerful tools, but it can also introduce unexpected behavior. Understanding these unique aspects of JavaScript will make you a more effective developer and help you write cleaner, more predictable code. Whether you’re working with closures, handling this, or managing async operations, JavaScript’s quirks are part of what makes it so versatile and rewarding to learn!

Leave a Reply

Your email address will not be published. Required fields are marked *