Back to JavaScript
2026-04-116 min read

Unintentional usage (JavaScript)

Learn Unintentional usage (JavaScript) step by step with clear examples and exercises.

Why This Matters

Understanding unintentional usage scenarios in JavaScript is crucial for writing robust, efficient, and maintainable code. By learning about common pitfalls, you'll be better prepared to write cleaner code that performs as intended, troubleshoot issues, debug your code, and prepare for job interviews or exams. This guide covers essential topics such as hoisting, truthy and falsy values, semicolons, strict mode, and more, explained with line-by-line code walkthroughs and practical examples.

Prerequisites

To get the most out of this guide, you should have a basic understanding of JavaScript syntax and variables. Familiarity with concepts such as functions, arrays, objects, and control structures like loops and conditional statements will also be helpful. If you're new to JavaScript, consider brushing up on these topics before diving into unintentional usage scenarios.

Fundamentals of JavaScript

  • Variables: let, const, var
  • Data Types: Numbers, Strings, Booleans, Arrays, Objects, Null, Undefined
  • Operators: Arithmetic, Comparison, Logical, Assignment
  • Control Structures: Conditional Statements (if, else if, else), Loops (for, while, for...of, forEach)
  • Functions: Function Declarations, Function Expressions, Arrow Functions

Core Concept

Hoisting

Hoisting is a mechanism in JavaScript that moves declarations to the top of their respective scope during the compilation phase. This means that variable and function declarations are hoisted, while assignments are not.

console.log(x); // undefined (variable declaration is hoisted)
var x = 10;

console.log(foo()); // undefined (function declaration is hoisted)
function foo() {
return 'Hello, World!';
}

In the example above, both x and foo are hoisted to the top of their respective scopes, allowing us to call console.log(x) and foo() before they've been assigned values. However, assignments are not hoisted, so attempting to use a variable before it's declared will result in an error.

console.log(bar); // ReferenceError: bar is not defined (assignment is not hoisted)
let bar = 20;

Truthy and Falsy Values

In JavaScript, certain values are considered truthy or falsy. These values can have unintended consequences when used in conditional statements or boolean contexts.

Truthy values include:

  • Any non-empty string (e.g., '0', 'false')
  • Numbers other than 0 and the special value NaN
  • Objects, arrays, and functions
  • Boolean true

Falsy values include:

  • The empty string ('')
  • Number 0 (0)
  • Boolean false
  • null and undefined
  • NaN
if ('') {
console.log('This will not execute'); // This will not execute
}

if (0) {
console.log('This will not execute'); // This will not execute
}

if (null) {
console.log('This will not execute'); // This will not execute
}

if (undefined) {
console.log('This will not execute'); // This will not execute
}

Semicolons

In JavaScript, semicolons are optional in most cases, but their omission can lead to unintended consequences known as "semicolon squashing." In some situations, the JavaScript engine may insert a semicolon where one is not present, leading to unexpected behavior.

let x = 10; // No semicolon here
let y = x + ; // Semicolon inserted by the JavaScript engine
console.log(y); // Outputs: undefined (because `;` is a no-op)

In the example above, the JavaScript engine inserts a semicolon after x, causing the expression + ; to be evaluated as a no-operation (;) rather than an assignment or arithmetic operation. To avoid this issue, always include semicolons at the end of your statements.

Strict Mode

Strict mode is a feature in JavaScript that disables certain behaviors and helps prevent unintentional usage issues. To enable strict mode, add "use strict" as the first line in your script or function.

// Enabling strict mode for an entire script
"use strict";

let x = 10; // No error (strict mode)
let y = undefined + 0; // TypeError: Cannot add undefined to number (strict mode)

In the example above, strict mode prevents the addition of undefined and a number, resulting in a TypeError.

Worked Example

Let's explore a real-world example where unintentional usage can lead to bugs in your code. We'll create a simple function that calculates the factorial of a given number using recursion:

function factorial(n) {
if (n === 0) return 1;
return n * factorial(n - 1);
}

console.log(factorial(5)); // Outputs: 120

However, this function contains an unintentional usage error. Can you spot it?

The issue lies in the recursive call to factorial(n - 1). If we pass a negative number as the argument, the function will not terminate due to an infinite loop:

console.log(factorial(-5)); // Outputs: RangeError: Maximum call stack size exceeded (the browser will eventually crash)

To fix this issue, we can add a check for negative numbers and return 0 in that case:

function factorial(n) {
if (n < 0) return 0;
if (n === 0) return 1;
return n * factorial(n - 1);
}

console.log(factorial(-5)); // Outputs: 0

Common Mistakes

Hoisting and Variable Shadowing

Hoisting can lead to variable shadowing, where a declared variable in the current scope obscures an identical variable in an outer scope. This can result in unexpected behavior when trying to access variables from the outer scope within the current scope.

let x = 10; // Global scope

function test() {
console.log(x); // Outputs: undefined (because `x` is shadowed by a local variable)
let x = 20; // Local scope
}

test();
console.log(x); // Outputs: 10 (accessing the global variable)

Truthy and Falsy Values in Conditional Statements

Using truthy and falsy values unintentionally can lead to unexpected behavior in conditional statements. Always ensure that your conditions are well-defined, using explicit boolean values or clear comparisons to avoid potential issues.

let x = 0;
if (x) {
console.log('This will execute'); // This will not execute
}

Semicolon Squashing

Omitting semicolons can lead to unintended consequences, such as semicolon squashing, where the JavaScript engine inserts a semicolon where one is not intended. To avoid this issue, always include semicolons at the end of your statements.

let x = 10; // No semicolon here
let y = x + ; // Semicolon inserted by the JavaScript engine
console.log(y); // Outputs: undefined (because `;` is a no-op)

Strict Mode and Function Declarations

In strict mode, function declarations are not hoisted like they are in non-strict mode. This means that calling a function before its declaration will result in an error in strict mode.

// Non-strict mode
foo(); // Outputs: undefined (function is hoisted)
function foo() {
console.log('Hello, World!');
}

// Strict mode
"use strict";
foo(); // ReferenceError: foo is not defined (function is not hoisted in strict mode)

Practice Questions

  1. What happens when you call console.log(undefined + 0)? Why does this behavior differ from other programming languages like Python or Java?
  2. Write a function called isEven that takes an integer as input and returns true if the number is even, and false otherwise. Be aware of potential unintentional usage issues in your implementation.
  3. Given the following code snippet:
let x = 10;
function test() {
console.log(x);
let x = 20;
}

test();
console.log(x);

What will be printed to the console, and why?

FAQ

Why does JavaScript allow optional semicolons?

JavaScript allows optional semicolons as a design choice to make it easier for developers transitioning from languages like Python or Java, where semicolons are required. However, this flexibility can lead to unintended consequences if not used carefully.

What is the difference between undefined and null in JavaScript?

In JavaScript, both undefined and null represent the absence of a value, but they are not equivalent. undefined represents a variable that has been declared but not assigned a value, while null is an explicit assignment that indicates the intentional absence of any object value.

Why does hoisting occur in JavaScript?

Hoisting occurs in JavaScript because it simplifies the parsing process for the JavaScript engine by moving declarations to the top of their respective scopes during the compilation phase. This allows variables and functions to be accessed before they've been assigned values, but assignments are not hoisted.

Unintentional usage (JavaScript) | JavaScript | XQA Learn