You can improve the function's time complexity at the expense of memory by tracking the duplicates in a separate [Set][1]. This will reduce the number of iterations by the number of unique items in the input array, and increase the memory need by the same number.

A further improvement can be gained if you delete duplicates from the unique set as you go. This will bring the memory use down.


<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

    function countDuplicates(original) {
      const uniqueItems = new Set();
      const duplicates = new Set();
      for (const value of original) {
        if (uniqueItems.has(value)) {
          duplicates.add(value);
          uniqueItems.delete(value);
        } else {
          uniqueItems.add(value);
        }
      }
      return duplicates.size;
    }


    /* Test code not related to solution */
    function test(name, func, data, result) {
      const output =  `${name} [${data.join(", ")}] : `;
      console.log(output + (func(data) === result ? "passed" : "failed")); 
    }


    test("1 duplicate ", countDuplicates, [9, 11, 12, 2, 7, 4, 2], 1);
    test("1 duplicate ", countDuplicates, [6, 6, 6], 1);
    test("2 duplicates ", countDuplicates, [0, 1, 4, 2, 7, 4, 2], 2);
    test("3 duplicates ", countDuplicates, [0, 1, 4, 2, 7, 4, 2, 0], 3);
    test("No duplicates ", countDuplicates, [0, 1, 4, 2, 7, 5, 8, 9], 0);

<!-- end snippet -->


  [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set