Question
I have an array of numbers, and I want to return only the unique values.
I found this code online, and it seems to work until the array contains 0. I also found a very similar version on Stack Overflow that does not fail.
How can I understand why this version breaks?
Array.prototype.getUnique = function () {
var o = {}, a = [], i, e;
for (i = 0; (e = this[i]); i++) {
o[e] = 1;
}
for (e in o) {
a.push(e);
}
return a;
};
In particular, why does the loop stop working when the array contains 0, and what is the correct modern JavaScript way to remove duplicates from an array?
Short Answer
By the end of this page, you will understand how to remove duplicate values from a JavaScript array, why some older looping patterns fail when values like 0 appear, and which modern approaches are safest and easiest to use. You will also learn how truthy and falsy values affect loop conditions and how to choose the right deduplication technique in real code.
Concept
The main concept behind this question is array deduplication and the related idea of truthy and falsy values in JavaScript.
The bug in the original code is not really about duplicates. It is about this loop condition:
for (i = 0; (e = this[i]); i++)
This code assigns this[i] to e, and then uses the assigned value as the loop condition. That means the loop continues only while e is truthy.
In JavaScript, these are examples of falsy values:
0""falsenullundefinedNaN
So if the array contains 0, then e = this[i] becomes 0, which is falsy, and the loop stops early.
Why this matters
In real programming, data often includes valid falsy values:
Mental Model
Think of a for loop condition like a security guard checking whether work should continue.
In the broken version, the guard says:
"Keep going only if the current value looks truthy."
That sounds okay until the value is 0. Even though 0 is a perfectly valid array element, the guard treats it like a stop signal.
A better mental model is:
"Keep going while the index is still inside the array."
That means you should check the position in the array, not the value stored there.
So this is fragile:
for (i = 0; (e = this[i]); i++)
And this is reliable:
for (i = 0; i < this.length; i++)
The first asks, "Is this value truthy?" The second asks, "Is this index valid?"
That is the key difference.
Syntax and Examples
Modern way: use Set
const numbers = [1, 2, 2, 3, 0, 0, 4];
const uniqueNumbers = [...new Set(numbers)];
console.log(uniqueNumbers); // [1, 2, 3, 0, 4]
Why this works
new Set(numbers)creates a set of unique values...spreads the set back into an array0is kept correctly becauseSetdoes not depend on truthiness
Older but valid approach: use filter
const numbers = [1, 2, 2, 3, 0, 0, 4];
const uniqueNumbers = numbers.filter( {
array.(value) === index;
});
.(uniqueNumbers);
Step by Step Execution
Consider this broken example:
const arr = [5, 2, 0, 9];
for (let i = 0, e; (e = arr[i]); i++) {
console.log("value:", e);
}
Step-by-step trace
Start
i = 0e = arr[0]→55is truthy, so the loop runs- Output:
value: 5
Next iteration
i = 1e = arr[1]→22is truthy, so the loop runs- Output:
value: 2
Next iteration
i = 2
Real World Use Cases
Removing duplicates from arrays is common in real applications.
Common scenarios
- User IDs: remove repeated IDs before querying a database
- Tags or categories: keep only unique labels from user input
- API results: merge data from multiple endpoints without duplicates
- Analytics: count unique page paths, events, or product IDs
- Form processing: clean repeated values from checkbox submissions
- Configuration lists: avoid duplicate feature flags or allowed roles
Example: unique tags
const tags = ["js", "css", "js", "html", "css"];
const uniqueTags = [...new Set(tags)];
console.log(uniqueTags); // ["js", "css", "html"]
Example: unique numeric IDs
const ids = [101, 203, 101, 404, 0, 404];
const uniqueIds = [...new Set(ids)];
console.log(uniqueIds);
Real Codebase Usage
In real codebases, developers usually avoid extending built-in prototypes unless there is a strong reason. So instead of this:
Array.prototype.getUnique = function () {
// ...
};
it is more common to write a reusable utility function:
function getUniqueValues(array) {
return [...new Set(array)];
}
Why utility functions are preferred
- They are easier to test
- They do not affect all arrays globally
- They reduce the risk of naming conflicts
- They are easier for teams to read and maintain
Common patterns in real projects
Validation before deduplication
function getUniqueValues(array) {
if (!Array.isArray(array)) {
throw new TypeError("Expected an array");
}
return [...new (array)];
}
Common Mistakes
1. Using the array value as the loop condition
Broken code:
for (let i = 0, e; (e = arr[i]); i++) {
console.log(e);
}
Why it fails
The loop stops at falsy values like 0, false, or "".
Fix
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
2. Forgetting that object keys become strings
Broken expectation:
const o = {};
o[1] = true;
o[2] = true;
console.log(Object.keys(o)); // ["1", "2"]
Why it matters
If you use an object for deduplication, numeric values come back as strings unless you convert them.
Comparisons
| Approach | Example | Handles 0 correctly | Keeps original types | Readability | Notes |
|---|---|---|---|---|---|
Set | [...new Set(arr)] | Yes | Yes | High | Best modern default |
filter + indexOf | arr.filter((v, i) => arr.indexOf(v) === i) | Yes | Yes | Medium | Common older approach |
| Object lookup | o[arr[i]] = true | Yes, if loop is correct |
Cheat Sheet
Remove duplicates
const unique = [...new Set(array)];
Safe classic loop
for (let i = 0; i < array.length; i++) {
const value = array[i];
}
Avoid this pattern
for (let i = 0, value; (value = array[i]); i++) {
// breaks on 0, false, "", null, undefined, NaN
}
Falsy values in JavaScript
0""falsenullundefinedNaN
Alternative deduplication
const unique = array.filter( arr.(value) === index);
FAQ
Why does 0 break the original loop?
Because 0 is a falsy value in JavaScript. The loop uses the assigned value itself as the condition, so it stops when the value is 0.
What is the easiest way to remove duplicates from a JavaScript array?
Use Set:
const unique = [...new Set(array)];
Is Set better than using an object?
Usually yes. Set is clearer, preserves types, and is designed specifically for unique values.
Why does the object-based method return strings?
Object keys are stored as strings, so numeric values like 1 and 2 come back as "1" and "2".
Should I add getUnique to Array.prototype?
Usually no. It is safer and more maintainable to use a normal function instead.
Does also work for removing duplicates?
Mini Project
Description
Build a small utility that cleans a list of product IDs by removing duplicates. This demonstrates safe array iteration, handling values like 0, and using the modern Set approach in a practical scenario.
Goal
Create a function that accepts an array of product IDs and returns a new array containing each ID only once, while preserving valid values such as 0.
Requirements
- Create a function named
getUniqueProductIds. - Accept an array of numbers as input.
- Return a new array with duplicates removed.
- Preserve valid falsy values such as
0. - Log the result for a sample input array.
Keep learning
Related questions
Adding Table Rows with jQuery: append(), Limits, and Best Practices
Learn how to add table rows in jQuery using append(), what elements are allowed in tables, and safer ways to build rows dynamically.
Bower vs npm: What’s the Difference in JavaScript Package Management?
Learn the plain difference between Bower and npm, how each manages packages, and why npm replaced Bower in most JavaScript projects.
Can `(a == 1 && a == 2 && a == 3)` Ever Be True in JavaScript?
Learn how JavaScript type coercion, loose equality, and custom object conversion can make `a == 1 && a == 2 && a == 3` true.