0

I already found the solution here by OhJeez: How to get an array of unique values from an array containing duplicates in JavaScript?

array.filter(function() {
  var seen = {};
  return function(element, index, array) {
    return !(element in seen) && (seen[element] = 1);
  };
}());

What I want to ask is how to make sense of the code above. The part I don't understand is how does var seen keep its keys. Wouldn't each iteration reset seen back to an empty hash/object?

Edit: I think I understand how closures work, and that does not solve my question. To my understanding, Array.prototype.filter loops each element of the array to the callback function, in this case the anonymous function 'var seen = {}; return function(element, index, array) {return !(element in seen) && (seen[element] = 1);};. This in turn returns the function inside.

My question, again, is shouldn't each iteration run the line 'var seen = {}'? Then how could seen keep its elements?

Dion Chan
  • 31
  • 5
  • 2
    Possible duplicate of [How do JavaScript closures work?](https://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Andreas Aug 26 '17 at 07:22
  • [What is the (function() { } )() construct in JavaScript?](https://stackoverflow.com/questions/8228281/what-is-the-function-construct-in-javascript) – Andreas Aug 26 '17 at 07:44

3 Answers3

0

This code is needlessly complex, and would stop even experienced JS programmers in their tracks for a minute as they tried to figure out what it is doing. Rewrite it as

function filter() {
  var seen = {};

  return array.filter(function(element, index, array) {
    return !(element in seen) && (seen[element] = 1);
  });
}

The point is that we need a hash (called seen here) and have to declare it somewhere. Normally, we would just declare it in some appropriate surrounding scope. For whatever reasons the programmer wanted to avoid doing that, so s/he introduced another scope around the function passed to filter. As I said, this is confusing and unnecessary.

  • Assuming your code meant function filter(array) {...} ; I certainly agree yours make sense. But I still want to know why the original code works – Dion Chan Aug 26 '17 at 07:40
0

Here we can explain this with two things.

  1. JS is language with function variable scope, so needed is visible inside anonymous function it is defined.
  2. Anonymous self-executing function that you can see as param to array.filter is used exactly to manage variable scope and to prevent needed from been reset every iteration. This function is called immediately and it returns the real callback for array.filter, but persisting needed in scope for this callback.

Anonymous self-executing functions is a huge tool in JS. You can learn more from, for example, this article.

Roman Osypov
  • 1,321
  • 12
  • 10
0
array.filter(function() {
  var seen = {};
  return function(element, index, array) {
    return !(element in seen) && (seen[element] = 1);
  };
}());

you can think of this as

var seen = {}
array.filter(function(element, index, array) {
    return !(element in seen) && (seen[element] = 1);
  })

Both will have same output only difference var seen remains a local scope in first case which is good.

when you call array.filter() the first parameter is a self invoked function which is evaluated before being passed to array.filter();

so it keeps seen in its closure.

Manoj
  • 1,175
  • 7
  • 11