Set.prototype.add()
set.add(value) The add() method inserts a new value into a Set object. If the value already exists, the Set remains unchanged. The method returns the Set itself, enabling powerful method chaining patterns.
Syntax
set.add(value)
Parameters
| Parameter | Type | Description |
|---|---|---|
value | any | The value to add to the Set |
Return Value
Returns the same Set object after the value has been added (or ignored if duplicate). This enables method chaining.
How uniqueness works
Sets use strict equality (===) to determine if a value already exists. This has important implications:
- Primitives (strings, numbers, booleans,
null,undefined, symbols, bigints): Compared by value - Objects (including arrays, functions, dates): Compared by reference, not by value
// Primitives: compared by value
const nums = new Set();
nums.add(1);
nums.add(1); // Ignored - already exists
nums.add('hello');
nums.add('hello'); // Ignored - already exists
console.log(nums.size); // 2
// Objects: compared by reference
const obj1 = { id: 1 };
const obj2 = { id: 1 };
const objects = new Set();
objects.add(obj1);
objects.add(obj2); // Added - different object reference!
console.log(objects.size); // 2
This reference-based comparison for objects means two seemingly identical objects are considered unique unless they’re the exact same reference in memory.
The uniqueness example above shows that add() silently ignores duplicates for primitives but treats separate object instances as distinct entries. The practical examples below demonstrate these rules in everyday use.
Examples
Basic usage with primitives
const fruits = new Set();
fruits.add('apple');
fruits.add('banana');
fruits.add('cherry');
console.log(fruits.size); // 3
console.log([...fruits]); // ['apple', 'banana', 'cherry']
Method Chaining
The return value of add() is the Set itself, which enables a compact pattern. Instead of repeating the variable name on every line, you can chain calls together — especially useful when seeding a collection with a fixed set of known values.
Since add() returns the Set, you can chain multiple calls:
const tags = new Set()
.add('javascript')
.add('typescript')
.add('rust');
console.log([...tags]); // ['javascript', 'typescript', 'rust']
Duplicates are ignored
Chaining is syntactic sugar — the underlying behavior doesn’t change. The core guarantee of add() is that duplicate values are silently dropped. This is what makes Sets the natural choice for uniqueness enforcement without any extra bookkeeping.
Adding a value that already exists has no effect:
const colors = new Set();
colors.add('red');
colors.add('blue');
colors.add('red'); // Ignored - already exists
console.log(colors.size); // 2
console.log([...colors]); // ['red', 'blue']
Adding objects (reference-based uniqueness)
Primitives are straightforward — same value, no add. Objects introduce a subtlety because JavaScript uses reference identity, not structural equality. Two objects with identical properties are different entries unless they share the same memory address.
Objects are added based on memory reference, not content:
const users = new Set();
const alice1 = { name: 'Alice', id: 1 };
const alice2 = { name: 'Alice', id: 1 }; // Same content, different reference
users.add(alice1);
users.add(alice2); // Added! Different object in memory
console.log(users.size); // 2
// But the same reference does nothing:
users.add(alice1); // Ignored - same reference
console.log(users.size); // 2
Reference-based uniqueness means you can track distinct object instances even when their data is identical. Sets also accept mixed types — numbers, strings, booleans, null, objects, arrays, and even functions can coexist in the same collection without any type restrictions.
Mixed Types
Sets can hold any JavaScript value:
const mixed = new Set()
.add(42)
.add('hello')
.add(true)
.add(null)
.add({ key: 'value' })
.add([1, 2, 3])
.add(() => 'function');
console.log(mixed.size); // 7
Mixed-type sets show how flexible the collection really is in practice. One of the most common practical patterns is using a Set to strip duplicates from an array — a concise one-liner that replaces manual loops and temporary lookup objects.
Common Patterns
Deduplicating Arrays
const nums = [1, 2, 2, 3, 4, 4, 5];
const unique = [...new Set(nums)];
console.log(unique); // [1, 2, 3, 4, 5]
Building a set dynamically
The spread-and-Set trick works when you have all data upfront. When values arrive over time — from user input, events, or a stream — call add() inside a loop to accumulate unique entries incrementally without pre-collecting everything into an array.
const input = ['a', 'b', 'a', 'c', 'b', 'd'];
const uniqueChars = new Set();
for (const char of input) {
uniqueChars.add(char);
}
console.log([...uniqueChars]); // ['a', 'b', 'c', 'd']
Tracking unique events
Loop-based accumulation gives you control over when and how values enter the Set. A practical extension of this pattern is tracking unique events — like visited pages or clicked elements — where the Set’s size works as a live counter of distinct items seen so far.
const viewedPages = new Set();
function visitPage(url) {
viewedPages.add(url);
console.log(`Now tracking ${viewedPages.size} unique pages`);
}
visitPage('/home'); // Now tracking 1 unique pages
visitPage('/about'); // Now tracking 2 unique pages
visitPage('/home'); // Now tracking 2 unique pages (duplicate ignored)
Why add() returns the set
add() returns the same Set instance so you can chain calls when building a collection from scratch. That makes it easy to create a compact setup sequence without repeating the variable name on every line. It also reinforces the idea that Set operations are mutating in place rather than creating a brand new collection every time.
Because the method returns the same object, you should be careful when reusing a Set across different parts of a program. Chaining is convenient during initialization, but it does not create a copy. If you need immutability, clone the Set first and mutate the clone instead.
Uniqueness and Identity
The identity rules are the real story behind add(). Primitives are compared by value, while objects are compared by reference. That means two objects with identical properties are still distinct entries unless they are the exact same object instance.
This behavior is useful for deduplication and tracking, but it also means you should choose your keys carefully. If the important part is an object field such as id, store that field instead of the whole object when you want value-based uniqueness.
Gotchas
- Object comparison is by reference: Two objects with identical content are considered different if they’re separate instances
- NaN handling: Interestingly,
NaNcan be added to a Set once—JavaScript’s===treatsNaNas equal to itself when used with Sets - Negative zero vs positive zero:
-0and+0are considered equal in Set operations
See Also
- Set.prototype.has() — check if a value exists
- Set.prototype.delete() — remove a value
- Set.prototype.clear() — remove all values