jsguides

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

ParameterTypeDescription
valueanyThe 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, NaN can be added to a Set once—JavaScript’s === treats NaN as equal to itself when used with Sets
  • Negative zero vs positive zero: -0 and +0 are considered equal in Set operations

See Also