call and apply in JavaScript: Top Mistakes and How to Avoid Them
Have you ever looked at someone else's JavaScript code and seen strange constructs like func.call(this, arg1, arg2) or func.apply(this, [arg1, arg2])? And wondered, "What's the difference, actually?" If so — you're not alone. The question "What is the difference between call and apply?" is one of the most popular on Stack Overflow with hundreds of thousands of views. And that's no accident.
Confusion between call and apply is a classic pitfall for beginners (and not only). In this article, we won't just cover the theory. We'll break down the top 5 real-world mistakes, show you how to fix them, and give you a clear algorithm that will forever eliminate the confusion. Let's go!
Quick Primer: What are call and apply?
Before diving into the mistakes, let's refresh the basics. The call and apply methods are built-in function methods in JavaScript. Their main task is to explicitly set the execution context (this) for a function. In other words, they allow you to say: "Hey function, pretend you're working with this object."
Syntax:
func.call(context, arg1, arg2, ...);func.apply(context, [arg1, arg2, ...]);Key difference:
callaccepts arguments comma-separated (a list).applyaccepts arguments as an array (or an array-like object).
That's it. This is the only difference. But it's precisely this "triviality" that causes most of the errors. Let's break them down.
Top 5 Mistakes When Working with call and apply
Mistake #1: Confusing the Argument List (Most Common!)
This is the "king" of all mistakes. You wrote a function that expects arguments one by one, but you pass an array using call. Or vice versa.
Disastrous Example:
function greet(greeting, punctuation) { console.log(greeting + ', ' + this.name + punctuation);}
const user = { name: 'Anna' };
// Mistake: passing an array but using callgreet.call(user, ['Hello', '!']); // Output: "Hello,! Anna,undefined" — complete nonsense!Why? call expects arguments one by one. It received one argument — the entire array — and placed it into the variable greeting. punctuation remained undefined.
How to fix? Use apply if the data is already in an array:
greet.apply(user, ['Hello', '!']); // Output: "Hello, Anna!" — correct!Or spread the array using the spread operator (modern approach):
greet.call(user, ...['Hello', '!']); // Also works!Mistake #2: Forgetting that apply Works with Array-Like Objects
Many think that apply accepts only a real array. In fact, it accepts any array-like object: it must have a length property and numeric keys.
Example:
function sum() { let total = 0; for (let i = 0; i < arguments.length; i++) { total += arguments[i]; } return total;}
// Passing not an array, but an object with lengthconst args = { 0: 5, 1: 10, 2: 15, length: 3 };
console.log(sum.apply(null, args)); // Output: 30 — works!But be careful: if the object has no length, apply will simply ignore it. This is a common mistake when working with arguments (a legacy object) or NodeList.
Mistake #3: Using call/apply Where a Simple Call Would Suffice
Sometimes beginners overuse