What is the difference between i++ and ++i in JavaScript and what do they return?

👨‍💻 Frontend Developer 🟡 Often Asked 🎚️ Easy
#JavaScript #JS Basics #Operators

Quick Answer

Increment operators ++ and decrement operators -- have two forms:

  • Postfix (i++, i--) — returns the old value, then modifies the variable
  • Prefix (++i, --i) — first modifies the variable, then returns the new value
let a = 5;
console.log(a++); // 5 (returns old value)
console.log(a);   // 6 (variable changed)
 
let b = 5;
console.log(++b); // 6 (returns new value)
console.log(b);   // 6 (variable already changed)

Key difference: timing of value return relative to variable modification.


Detailed Explanation of Operators

Postfix Form (i++, i—)

Algorithm:

  1. Remembers current value of the variable
  2. Increases/decreases variable by 1
  3. Returns remembered (old) value
let counter = 10;
 
// Postfix increment
let oldValue = counter++;
console.log(oldValue); // 10 (old value)
console.log(counter);  // 11 (new value)
 
// Postfix decrement
let score = 100;
let previousScore = score--;
console.log(previousScore); // 100 (old value)
console.log(score);         // 99 (new value)

Prefix Form (++i, —i)

Algorithm:

  1. Increases/decreases variable by 1
  2. Returns new value of the variable
let counter = 10;
 
// Prefix increment
let newValue = ++counter;
console.log(newValue); // 11 (new value)
console.log(counter);  // 11 (same value)
 
// Prefix decrement
let score = 100;
let updatedScore = --score;
console.log(updatedScore); // 99 (new value)
console.log(score);        // 99 (same value)

Comparison Table

OperatorNameWhen ModifiedWhat ReturnsExample
i++Postfix incrementAfter returnOld value5++ → returns 5, i becomes 6
++iPrefix incrementBefore returnNew value++5i becomes 6, returns 6
i--Postfix decrementAfter returnOld value5-- → returns 5, i becomes 4
--iPrefix decrementBefore returnNew value--5i becomes 4, returns 4

Practical Examples

Example 1: In Loops

// Postfix form (classic loop)
for (let i = 0; i < 5; i++) {
  console.log(i); // 0, 1, 2, 3, 4
}
 
// Prefix form
for (let i = 0; i < 5; ++i) {
  console.log(i); // 0, 1, 2, 3, 4
}
 
// In loops the result is the same,
// since the return value is not used

Example 2: In Expressions

let a = 5;
let b = 5;
 
// Postfix form
let result1 = a++ * 2;
console.log(result1); // 10 (5 * 2)
console.log(a);       // 6
 
// Prefix form
let result2 = ++b * 2;
console.log(result2); // 12 (6 * 2)
console.log(b);       // 6

Example 3: In Conditions

let attempts = 3;
 
// Postfix form
if (attempts-- > 0) {
  console.log(`Attempt ${attempts + 1}`); // "Attempt 3"
  console.log(`Attempts left: ${attempts}`); // "Attempts left: 2"
}
 
let retries = 3;
 
// Prefix form
if (--retries > 0) {
  console.log(`Attempt ${3 - retries}`); // "Attempt 1"
  console.log(`Attempts left: ${retries}`); // "Attempts left: 2"
}

Example 4: With Arrays

let arr = [10, 20, 30, 40, 50];
let index = 2;
 
// Postfix form
console.log(arr[index++]); // 30 (arr[2])
console.log(index);        // 3
 
index = 2; // reset
 
// Prefix form
console.log(arr[++index]); // 40 (arr[3])
console.log(index);        // 3

Complex Expressions

Combining Operators

let x = 5;
let y = 5;
 
// Complex expression with postfix
let result1 = x++ + x++ + x++;
// x++ returns 5, x becomes 6
// x++ returns 6, x becomes 7  
// x++ returns 7, x becomes 8
// result1 = 5 + 6 + 7 = 18
console.log(result1); // 18
console.log(x);       // 8
 
// Complex expression with prefix
let result2 = ++y + ++y + ++y;
// ++y: y becomes 6, returns 6
// ++y: y becomes 7, returns 7
// ++y: y becomes 8, returns 8
// result2 = 6 + 7 + 8 = 21
console.log(result2); // 21
console.log(y);       // 8

Mixed Operators

let a = 10;
let b = 10;
 
// Mixing prefix and postfix
let mixed = a++ + ++a - --b + b--;
// a++ returns 10, a becomes 11
// ++a: a becomes 12, returns 12
// --b: b becomes 9, returns 9
// b-- returns 9, b becomes 8
// mixed = 10 + 12 - 9 + 9 = 22
 
console.log(mixed); // 22
console.log(a);     // 12
console.log(b);     // 8

Practical Tasks

Task 1: What will the console output?

let i = 5;
let j = i++ + ++i;
console.log(j);
console.log(i);
Answer

Result:

Explanation:

  • i++ returns 5, then i becomes 6
  • ++i increases i to 7 and returns 7
  • j = 5 + 7 = 12

Task 2: Loop Analysis

let count = 0;
for (let i = 0; i < 3; i++) {
  count += i++;
}
console.log(count);
Answer

Result: count = 3

Explanation:

  • Iteration 1: i = 0, count += 0 (i++ returns 0), i becomes 1, then i++ in loop makes i = 2
  • Iteration 2: i = 2, count += 2 (i++ returns 2), i becomes 3, loop ends
  • count = 0 + 2 = 2

Warning: Double increment in loops is bad practice!

Task 3: Array and Indices

let arr = ['a', 'b', 'c', 'd'];
let index = 1;
let result = arr[index++] + arr[++index];
console.log(result);
console.log(index);
Answer

Result:

Explanation:

  • x++ returns 5, x becomes 6
  • 5 > 5 is false
  • ++y increases y to 6, returns 6
  • 6 > 5 is true
  • Since it’s || (OR), condition is met

Real-World Applications

1. Counters and Iterators

// Classic counter
let pageViews = 0;
 
function trackPageView() {
  console.log(`Page view #${++pageViews}`);
  // Prefix is convenient when you need the new value
}
 
// Processing elements in&nbsp;order
let items = ['item1', 'item2', 'item3'];
let currentIndex = 0;
 
function getNextItem() {
  if (currentIndex < items.length) {
    return items[currentIndex++]; // Postfix to&nbsp;get current element
  }
  return null;
}

2. ID Generators

class IdGenerator {
  constructor() {
    this.currentId = 0;
  }
  
  // Prefix form for&nbsp;generating new ID
  generateId() {
    return `id_${++this.currentId}`;
  }
  
  // Postfix form to&nbsp;get current ID&nbsp;and move to&nbsp;next
  getCurrentAndNext() {
    return {
      current: `id_${this.currentId++}`,
      next: `id_${this.currentId}`
    };
  }
}
 
const generator = new IdGenerator();
console.log(generator.generateId()); // "id_1"
console.log(generator.generateId()); // "id_2"

3. Algorithms and Data Structures

// Stack implementation
class Stack {
  constructor() {
    this.items = [];
    this.top = -1;
  }
  
  push(item) {
    this.items[++this.top] = item; // Prefix: first increment, then use
  }
  
  pop() {
    if (this.top >= 0) {
      return this.items[this.top--]; // Postfix: first use, then decrement
    }
    return undefined;
  }
  
  peek() {
    return this.items[this.top];
  }
}
 
// Array search
function findElement(arr, target) {
  let left = 0;
  let right = arr.length - 1;
  let comparisons = 0;
  
  while (left <= right) {
    console.log(`Comparison #${++comparisons}`); // Prefix for&nbsp;counting
    
    let mid = Math.floor((left + right) / 2);
    
    if (arr[mid] === target) {
      return { index: mid, comparisons };
    } else if (arr[mid] < target) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }
  
  return { index: -1, comparisons };
}

4. Event Handling

// Debouncing with counter
function createDebouncedFunction(func, delay) {
  let timeoutId;
  let callCount = 0;
  
  return function(...args) {
    clearTimeout(timeoutId);
    
    timeoutId = setTimeout(() => {
      console.log(`Call #${++callCount}`); // Prefix for&nbsp;new number
      func.apply(this, args);
    }, delay);
  };
}
 
// Retry limit
function createRetryFunction(func, maxAttempts) {
  let attempts = 0;
  
  return async function(...args) {
    while (attempts < maxAttempts) {
      try {
        console.log(`Attempt ${++attempts}`); // Prefix for&nbsp;current attempt
        return await func.apply(this, args);
      } catch (error) {
        if (attempts >= maxAttempts) {
          throw new Error(`Maximum attempts exceeded (${maxAttempts})`);
        }
        console.log(`Attempt ${attempts} failed, retrying...`);
      }
    }
  };
}

Performance and Optimization

Prefix vs Postfix Performance

In JavaScript there’s no performance difference between ++i and i++ for primitive types, because:

  • Both operators compile to the same bytecode
  • V8 and other engines optimize both variants equally
  • The difference exists only in C++, where postfix creates a temporary copy
// Benchmark (results will be&nbsp;approximately the&nbsp;same)
function benchmarkPrefix() {
  let sum = 0;
  for (let i = 0; i < 1000000; ++i) {
    sum += i;
  }
  return sum;
}
 
function benchmarkPostfix() {
  let sum = 0;
  for (let i = 0; i < 1000000; i++) {
    sum += i;
  }
  return sum;
}
 
// Execution time will be&nbsp;practically the&nbsp;same
console.time('prefix');
benchmarkPrefix();
console.timeEnd('prefix');
 
console.time('postfix');
benchmarkPostfix();
console.timeEnd('postfix');

When to Choose Prefix or Postfix

// ✅ Use prefix when you need the&nbsp;new value
let counter = 0;
function getNextId() {
  return `user_${++counter}`; // Immediately get new value
}
 
// ✅ Use postfix when you need the&nbsp;current value
let index = 0;
let items = ['a', 'b', 'c'];
function getNextItem() {
  return items[index++]; // Get current element, then move to&nbsp;next
}
 
// ✅ In loops — no&nbsp;difference, choose by&nbsp;team style
for (let i = 0; i < 10; i++) { /* postfix — classic */ }
for (let i = 0; i < 10; ++i) { /* prefix — C++ style */ }

Common Mistakes and Pitfalls

1. Misunderstanding Return Values

Mistake: Expecting same behavior

let a = 5;
let b = 5;
 
// Wrong expectation of&nbsp;same result
let result1 = a++ * 2; // 10 (5 * 2)
let result2 = ++b * 2; // 12 (6 * 2)
 
// result1 !== result2!

Correct: Understanding the difference in timing of value return

2. Double Increment in Loops

// ❌ Bad: double increment
for (let i = 0; i < 10; i++) {
  console.log(i++);
  // i is&nbsp;incremented twice per iteration!
}
 
// ✅ Good: single increment
for (let i = 0; i < 10; i++) {
  console.log(i);
}
 
// ✅ Or alternatively:
for (let i = 0; i < 10; ++i) {
  console.log(i);
}

3. Using in Complex Expressions

// ❌ Bad: hard to&nbsp;read and&nbsp;understand
let x = 5;
let result = x++ + ++x * x-- - --x;
 
// ✅ Good: break into steps
let y = 5;
let step1 = y++; // 5, y = 6
let step2 = ++y; // 7, y = 7  
let step3 = y--; // 7, y = 6
let step4 = --y; // 5, y = 5
let clearResult = step1 + step2 * step3 - step4;

4. Variable Modification in One Expression

// ❌ Undefined behavior: don't do&nbsp;this!
let i = 5;
let bad = i++ + i++ + ++i; // Order of&nbsp;evaluation not guaranteed
 
// ✅ Good: one modification per expression
let j = 5;
let good1 = j++; // 5
let good2 = j++; // 6  
let good3 = ++j; // 8
let goodResult = good1 + good2 + good3; // 19

5. Increment in Conditions

// ⚠️ Careful: may be&nbsp;non-obvious
let attempts = 3;
while (attempts-- > 0) {
  console.log(`Attempt ${attempts + 1}`); // Need +1 because of&nbsp;postfix
}
 
// ✅ More clear:
let retries = 3;
while (retries > 0) {
  console.log(`Attempt ${retries}`);
  retries--;
}

Modern Alternatives

Using Array Methods

// Instead of&nbsp;manual increment in&nbsp;loops
const numbers = [1, 2, 3, 4, 5];
 
// ❌ Old style
for (let i = 0; i < numbers.length; i++) {
  console.log(numbers[i] * 2);
}
 
// ✅ Modern style
numbers.forEach(num => console.log(num * 2));
numbers.map(num => num * 2);
numbers.filter(num => num > 2);

Destructuring and Spread

// Instead of&nbsp;manual index management
const items = ['a', 'b', 'c', 'd'];
 
// ❌ With increment
let index = 0;
const first = items[index++];
const second = items[index++];
 
// ✅ With destructuring
const [firstItem, secondItem, ...rest] = items;

Generators for Counters

// ✅ Modern approach to&nbsp;counters
function* createCounter(start = 0) {
  let count = start;
  while (true) {
    yield ++count;
  }
}
 
const counter = createCounter();
console.log(counter.next().value); // 1
console.log(counter.next().value); // 2
console.log(counter.next().value); // 3
 
// Or with class
class Counter {
  constructor(start = 0) {
    this.value = start;
  }
  
  next() {
    return ++this.value;
  }
  
  current() {
    return this.value;
  }
}

Best Practices

1. Prefer Clarity Over Performance

// ✅ Good: clear what's happening
let index = 0;
while (index < items.length) {
  processItem(items[index]);
  index++;
}
 
// ⚠️ Less clear
let i = 0;
while (i < items.length) {
  processItem(items[i++]);
}

2. Use Meaningfully

// ✅ Postfix: when you need current value
function popFromStack(stack) {
  return stack[--stack.length]; // Prefix: first decrease size
}
 
function pushToStack(stack, item) {
  stack[stack.length++] = item; // Postfix: use current length, then increase
}
 
// ✅ Prefix: when you need new value
function generateUniqueId() {
  return `item_${++globalCounter}`; // Get next ID
}

3. Be Consistent

// ✅ Choose one style for&nbsp;loops and&nbsp;stick to&nbsp;it
// Team prefers postfix:
for (let i = 0; i < length; i++) { /* ... */ }
for (let j = 0; j < count; j++) { /* ... */ }
 
// Team prefers prefix:
for (let i = 0; i < length; ++i) { /* ... */ }
for (let j = 0; j < count; ++j) { /* ... */ }

4. Document Complex Usage

// ✅ When using in&nbsp;complex scenarios, add comments
function processQueue() {
  // Use postfix to&nbsp;get current item before moving to&nbsp;next
  while (queue.length > 0) {
    const item = queue[currentIndex++];
    process(item);
    
    // Use prefix to&nbsp;increment attempt counter before check
    if (++attempts > maxAttempts) {
      break;
    }
  }
}

Conclusion

Key Points

  1. Postfix (i++, i--) returns old value, then modifies
  2. Prefix (++i, --i) modifies first, then returns new value
  3. In loops — no functional difference, choose by style
  4. In expressions — significant difference in returned values
  5. Performance — no difference in JavaScript for primitives

When to Use

  • Postfix: When you need the current value before modification
  • Prefix: When you need the new value after modification
  • Loops: Either form, be consistent with team style
  • Complex expressions: Avoid or break into clear steps

Modern Alternatives

  • Array methods (forEach, map, filter) instead of manual loops
  • Destructuring instead of index manipulation
  • Generators for advanced counter scenarios
  • Classes with explicit methods for state management

Remember: clarity and maintainability are more important than micro-optimizations. Choose the form that makes your intent clearest to other developers.

Want more articles on interview preparation?
FollowEasyAdvice, bookmark the site, and level up every day 💪