Set.prototype.add()

Inserts a value if it is not already present, and returns the same collection so calls can chain.

Signature
add(value)
  • Added in JavaScript ES2015

Parameters

ParameterTypeDescription
$valueanyThe value to add. Objects are compared by reference, not by value. If an equal value (SameValueZero) is already present, the collection is left unchanged.

Return value

SetThe same Set object, which makes calls chainable.

Errors

Throws a TypeError if called on a value that is not a real Set instance.

add() is the only way to grow a Set after construction. It is idempotent: adding a value that is already a member does nothing and is not an error, so you never need to guard it with a has() check. Writing if (!s.has(x)) s.add(x) is redundant work.

The return value is the collection itself, not a boolean and not the value. That is what makes s.add(1).add(2).add(3) legal, and it is also the thing that surprises people: there is no way to learn from the return value whether the insert actually changed anything. If you need that, compare size before and after, or call has() first.

Ordering

Insertion order is preserved and stable. Re-adding an existing value does not move it to the end — the position from the first successful insert is kept. If you want most-recently-used ordering (an LRU cache, for instance), delete the value and add it again.

Adding during iteration

A value added while a for...of loop or forEach() is still running will be visited by that same loop. This is well defined, but it makes an unconditional add inside a loop over the same collection an infinite loop.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Accumulate the distinct error codes seen while validating a batch
  • Mark graph nodes visited inside a breadth-first search
  • Build a tag collection from user clicks without checking for repeats
  • Collect the unique keys present across a list of heterogeneous objects

Frequently asked questions

Does add() overwrite a value that is already in the Set?

No — if an equal value is already present, the collection is left completely unchanged and the original stays in its original insertion position. The call is a silent no-op, not an error.

Why does add() return the Set instead of true or false?

So that calls can be chained, as in s.add(1).add(2). To find out whether the value was actually new, compare size before and after the call, or test with has() first.

Can I add to a Set while looping over it?

Yes, and the running loop will visit the newly added values — which means an unconditional add inside a for...of over the same collection never terminates. Iterate a copy if you need to add safely.

More examples

Detecting whether the add was new

Since add() always returns the Set, the size comparison is the cheapest way to detect a real insertion. The output shows false for the duplicate "a" and true for the new "b".

Example · javascript
const seen = new Set(["a"]);

function addNew(set, value) {
  const before = set.size;
  set.add(value);
  return set.size !== before;
}

console.log(addNew(seen, "a"));
console.log(addNew(seen, "b"));
console.log([...seen]);

Objects go in by reference

The same reference added twice counts once, but a fresh literal with identical contents counts separately, giving size 2. Mutating a stored object after insertion is visible through the Set — it holds the reference, not a snapshot.

Example · javascript
const shapes = new Set();
const circle = { kind: "circle" };

shapes.add(circle);
shapes.add(circle);
shapes.add({ kind: "circle" });

console.log(shapes.size);
console.log(shapes.has(circle));
console.log(shapes.has({ kind: "circle" }));

circle.kind = "ellipse";
console.log([...shapes][0]);

Refreshing recency by delete-then-add

A plain add() on an existing member keeps its original position, so "alpha" only moves to the end once it has been deleted first. This delete-then-add pair is the standard trick for maintaining most-recently-used order.

Example · javascript
const recent = new Set(["alpha", "beta", "gamma"]);

function touch(set, value) {
  set.delete(value);
  set.add(value);
}

touch(recent, "alpha");
console.log([...recent]);

touch(recent, "delta");
console.log([...recent]);

Discussion

  • Be the first to comment on this lesson.