
10 JavaScript Quirks That Look Wrong (But Are Actually Right)
This article dives deep into ten surprising quirks of JavaScript that might confuse developers, especially those new to the language. From unexpected behavior with type coercion to peculiarities in operator precedence, we will clarify each aspect with real-world examples and practical implications. By understanding these quirks, developers can write cleaner and more efficient code, avoiding common pitfalls along the way.

Dev Orbit
July 19, 2025
Introduction
JavaScript is a language full of hidden quirks and unexpected behaviors that can lead to frustrating bugs and confusion among developers. For newcomers, or even for seasoned veterans, these quirks can seem wrong at first glance. However, understanding these peculiarities can help developers harness the full power of JavaScript and write better, more reliable code. This article aims to shed light on ten such quirks that might initially appear erroneous but are, in fact, correct according to JavaScript's design principles. By demystifying these aspects, we promise to enhance your understanding and competence in JavaScript development.
1. The `==` and `===` Confusion
One of the most baffling aspects of JavaScript is the difference between the `==` (abstract equality) and `===` (strict equality) operators. While they are both used for comparison, they behave quite differently.
`==` checks for equality of value and performs type coercion if types don't match.
`===` checks for equality of both value and type, without type coercion.
For example:
console.log(5 == '5'); // true
console.log(5 === '5'); // false
This can lead to unexpected outcomes, causing bugs in applications. To avoid confusion, it is a best practice to always use `===` to ensure strict equality checks and maintain code clarity.
2. `null` vs. `undefined`
Understanding the difference between `null` and `undefined` is essential for JavaScript developers. While both represent the absence of a value, they are used in different contexts:
`null` is an assigned value, indicating that a variable intentionally has no value.
`undefined` indicates that a variable has been declared but has not yet been assigned a value.
This distinction might seem trivial but can have significant implications in your code:
let x; // x is undefined
let y = null; // y is null
console.log(x == null); // true
console.log(y == null); // true
For safer comparisons, it’s advisable to use explicit checks to distinguish between the two types clearly.
3. The `this` Keyword
Many developers struggle with the `this` keyword, particularly how its value changes based on context. In JavaScript, `this` refers to the object that is executing the current function. This can change based on how a function is called:
When invoked as a method of an object, `this` refers to that object.
When invoked in a function context, `this` refers to the global object (or `undefined` in strict mode).
For instance:
const obj = {
name: 'JavaScript',
logName: function () {
console.log(this.name);
}
};
obj.logName(); // 'JavaScript'
const log = obj.logName;
log(); // undefined (or ReferenceError in strict mode)
To mitigate confusion around `this`, developers can use arrow functions, which do not have their own `this` but inherit it from their enclosing context.
4. Array and Object Comparisons
In JavaScript, when comparing objects and arrays, many developers expect a simple equality check. However, this is not the case, as objects and arrays are reference types.
For example, two identical arrays will not be considered equal since they reference different memory locations:
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
console.log(arr1 == arr2); // false
This can lead to unexpected outcomes, especially in condition checks. A common approach to compare arrays is to use utility libraries like Lodash, or to write a custom comparison function. Caution is advised as performance implications can arise with deep comparisons.
5. Type Coercion and Truthy/Falsy Values
JavaScript performs automatic type coercion in many scenarios, particularly with comparison operators and logical constructs. This can often lead to confusing behavior for those unfamiliar with the concept of truthy and falsy values.
Falsy values in JavaScript include: false, 0, "", null, undefined, and NaN.
Truthy values are all values that are not falsy.
For example:
if (0) {
console.log('This will not run');
}
if ('hello') {
console.log('This will run');
}
Understanding these types can prevent what may seem like silly mistakes. It is beneficial to explicitly check values rather than relying on their truthiness to increase code readability.
6. The Weirdness of NaN
Another quirk of JavaScript involves the Not-a-Number (NaN) value. Developers often expect `NaN` to behave like a regular number; however, it has unique properties:
NaN is not equal to anything, including itself:
console.log(NaN === NaN); // false
To check if a value is NaN, the
isNaN()
function can be used.
For example:
console.log(isNaN(NaN)); // true
console.log(isNaN(123)); // false
Due to these properties, using NaN might lead to some unexpected behavior in mathematical operations. Always validate your inputs to mitigate these issues.
7. The Curiosities of Scope
JavaScript has function scope, block scope, and the peculiar behavior of hoisting, which can often baffle developers. Hoisting means that variable declarations are moved to the top of their containing function or block during compile time.
This can lead to instances where you can reference a variable before it is defined:
console.log(x); // undefined
var x = 5;
This can be a surprising outcome for many, and it reinforces the importance of declaring variables at the top of their scope to avoid confusion. With the introduction of let and const, which are block-scoped and don’t hoist in the same manner, developers should consider using them to avoid some of the pitfalls associated with `var`.
8. The Function of Functions as First-Class Citizens
JavaScript treats functions as first-class citizens, meaning functions can be treated like any other variable. This feature allows for a powerful style of programming but can lead to confusion.
For example, functions can be assigned to variables, passed as arguments, or returned from other functions:
function greet(name) {
return `Hello, ${name}`;
}
const greetFunc = greet;
console.log(greetFunc('World')); // 'Hello, World'
Understanding how functions can interact and manipulate each other creates potential for powerful design patterns like callbacks and higher-order functions, rewarding developers who embrace them.
9. Event Loop and Asynchronous JavaScript
The concept of the event loop is fundamental to asynchronous programming in JavaScript. However, it can also create significant confusion. JavaScript is single-threaded but leverages a callback queue and callback functions to handle asynchronous tasks:
This leads to the situation where asynchronous code might execute after synchronous code has completed:
console.log('Start');
setTimeout(() => {
console.log('Timeout');
}, 0);
console.log('End');
The output will be: Start, End, Timeout, which can be misleading for those unfamiliar with how the event loop manages tasks towards its execution context.
10. Closure Behavior
Closures are a staple of JavaScript programming, allowing functions to retain access to their parent scope even after that parent function has executed. This can lead to unexpected behaviors if misunderstood:
For example, if a closure is created within a loop, all iterations might refer to the same instance:
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // Logs 3 three times
}, 100);
}
This happens because `var` is function-scoped, meaning all closures share the same `i`. Using `let` will create a new scope for each iteration, resolving the issue.
Bonus/Advanced Tips
While understanding these quirks can be enlightening, it’s beneficial to apply a few advanced techniques to enhance your JavaScript programming skills:
Favour `===` over `==`: Making this a habit can save you from unexpected type coercions.
Explicitly define variable scopes: Use
let
andconst
to avoid unexpected behaviors associated with hoisting and scope.Utilize helper functions: Libraries like Lodash can simplify complex comparisons and manipulations.
Always test your code thoroughly and consider edge cases where these quirks can lead to confusing outcomes.
Conclusion
In conclusion, JavaScript is a language rich with quirks that can oftentimes confound even experienced developers. Understanding the subtleties of operators, types, and scope allows for writing cleaner and more effective code. By mastering these peculiarities, you can prevent bugs before they arise and unlock the true potential of JavaScript in your projects. Join the conversation below by sharing your experiences, insights, or questions as we navigate through these fascinating quirks together!

Enjoyed this article?
Subscribe to our newsletter and never miss out on new articles and updates.
More from Dev Orbit

Tamron 16–30mm F/2.8 Di III VXD G2 for Sony E-Mount Listed for Pre-Order on Amazon US
Discover the latest offering in wide-angle photography with the Tamron 16–30mm F/2.8 Di III VXD G2 lens for Sony E-Mount, now available for pre-order on Amazon US. This article delves deep into its specifications, unique features and its potential impact on your photographic journey. From its advanced optical design to performance benchmarks, we’ll explore everything that makes this lens a must-have for both amateur and professional photographers.

Raed Abedalaziz Ramadan: Steering Saudi Investment Toward the Future with AI and Digital Currencies
In an era marked by rapid technological advancements, the intersection of artificial intelligence and digital currencies is reshaping global investment landscapes. Industry leaders like Raed Abedalaziz Ramadan are pioneering efforts to integrate these innovations within Saudi Arabia’s economic framework. This article delves into how AI and digital currencies are being leveraged to position Saudi investments for future success, providing insights, strategies and practical implications for stakeholders.

Unlocking WASI: The Future of Serverless with WebAssembly
Discover how WASI is transforming serverless computing with secure, portable WebAssembly runtimes for the cloud era.

The Network Evolution: Traditional vs. Automated Infrastructure
Discover the revolution from traditional to automated network infrastructures, learn the benefits, challenges and advanced strategies for seamless transition.
9 Real-World Python Fixes That Instantly Made My Scripts Production-Ready
In this article, we explore essential Python fixes and improvements that enhance script stability and performance, making them fit for production use. Learn how these practical insights can help streamline your workflows and deliver reliable applications.

Mastering Git Hooks for Automated Code Quality Checks and CI/CD Efficiency
Automate code quality and streamline your CI/CD pipelines with Git hooks. This step-by-step tutorial shows full-stack developers, DevOps engineers, and team leads how to implement automated checks at the source — before bad code ever hits your repositories.
Releted Blogs

9 Powerful Reasons Why NestJS Beats Other Backend Frameworks in 2025
NestJS is revolutionizing how developers approach backend development in 2025. With built-in TypeScript support, modular architecture and first-class microservices integration, it's more than just a framework—it's a complete platform for building enterprise-grade, scalable applications. Discover why NestJS outshines Express, Django, Laravel and other backend giants in this in-depth comparison.

NestJS vs Express: Choosing the Right Backend Framework for Your Next Project
Are you torn between NestJS and Express for your next Node.js project? You're not alone. Both are powerful backend frameworks—but they serve very different purposes. This deep-dive comparison will help you decide which one fits your project's size, complexity and goals. Whether you're building a startup MVP or scaling a microservice architecture, we’ve covered every angle—performance, learning curve, architecture, scalability, testing and more.
Have a story to tell?
Join our community of writers and share your insights with the world.
Start Writing