Search code examples
javascriptecmascript-6setecmascript-5

Duplication of items in a Javascript Set


I was going through basics of Javscript Set.According to its defintion, A Set is a special type collection – “set of values” (without keys), where each value may occur only once.

But I see when it comes to reference types the behavior is different. Consider the following snippet:

let set = new Set();
let john = { name: "John" };
let pete = { name: "Pete" };
let mary = { name: "Mary" };
set.add(john);
set.add(pete);
set.add(mary);
set.add(john);
set.add(mary);
console.log("Scenario 1");
for (let user of set) {
  console.log(user.name);
}

let set1 = new Set();
set1.add({ name: "John" });
set1.add({ name: "Pete" });
set1.add({ name: "Mary" });
set1.add({ name: "John" });
console.log("Scenario 2");
for (let user of set1) {
  console.log(user.name);
}

I see in the scenario 1, it wont allow duplicates to be added as they are the same references. But in scenario 2 I see duplicates are being added.

Can some explain this behavior? Or Am I missing something.

How scenario 1 is different from 2?


Solution

  • A Set does not look at the contents of the object itself. It only looks at the pointer to the object.

    If it's not a pointer to the same physical object, then it's allowed to be added to the Set as a different physical object. In fact, you can add an object to the set and then change it's contents afterwards because the fact that it's in the set has NOTHING to do with the contents of the object, only the physical pointer to the object. If it's not the same pointer to the same object, then it can be added separately.

    Here's an example:

    let s = new Set();
    let x1 = {name: "John"};
    let x2 = {name: "John"};
    
    console.log(x1 === x2);    // false, not the same physical object
    
    s.add(x1);
    console.log(s.has(x1));    // true
    console.log(s.has(x2));    // false
    s.add(x2);
    console.log(s.has(x2));    // true
    console.log(Array.from(s));      // [{name: "John"}, {name: "John"}];
    
    // now modify x1
    x1.name = "Bob";
    // the x1 object is still in the set, even though you modified it
    // because being in the set has NOTHING to do with the contents of the object at all
    console.log(s.has(x1));    // true
    console.log(Array.from(s));   // [{name: "Bob"}, {name: "John"}];