1

I'm trying to use Closure in JS in order to declare a function named **expandArray()** which contain an Array named **myArray**and Returns an anonymous function that directly modifies myArray by increase the values by 1 than the returned function then returns the value of **myArray**. My Problem here one the last part where the returned function return a function not Array value ?!

This is my code

function expandArray() {
  const myArray = [1, 1, 1];

  return function () {
    myArray.forEach( function (num, index, myArray) {
        myArray[index] = num + 1;
    });
    return myArray;
  };
}

console.log(expandArray());
Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
  • 1
    `map` doesn't mutate, it returns a new array, write `return myArray.map`, not the unmodified myArray – Icepickle Jul 27 '18 at 16:19
  • sorry map should be forEach –  Jul 27 '18 at 16:20
  • @Icepickle `.map()` is only used to iterate over the elements in the array. The returned array will only contain `undefined`s – Andreas Jul 27 '18 at 16:21
  • 1
    This works as expected if you call the function that is returned `expandArray()()` – Mark Jul 27 '18 at 16:23
  • 2
    This code does exactly what you told it to do: the `expandArray` function returns a function. And running _that_ function will return a reference to the internal array. – Mike 'Pomax' Kamermans Jul 27 '18 at 16:24
  • Sorry i did not understand the question correctly in first part the question ask me to add another value to myArray and i increase the myArray values which is wrong. thank you for the help :) –  Jul 27 '18 at 16:35

7 Answers7

2

As its closure, you have invoked it only once like expandArray() , which return the function itself, which is below

ƒ () {
    myArray.map( function (num, index, myArray) {
        myArray[index] = num + 1;
    });
    return myArray;
  }

you need to invoke it again to get your result back as below

expandArray()() //[2, 2, 2]

Ref: How do JavaScript closures work?

Shushanth Pallegar
  • 2,832
  • 1
  • 14
  • 16
1

You've written a function that returns a function when you run it:

function expandArray() {
  const myArray = [...];
  // return this when we run expandArray():
  return function() {
    ...
  }
}

So if you run expandArray(), it is going to return your anonymous function. Exactly as you wrote it to do.

If you then want to get an actual reference to that internal myArray, you'll now need to actually run that returned function, so:

var getMyArray = expandArray();
var result = getMyArray();
console.log(result);
Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
0

In your original code, you're only getting the return value of expandArray(), which is the function you're trying to use as a closure. In order to get the closure's return value, try this out:

function expandArray() {
  const myArray = [1, 1, 1];

  return function () {
    myArray.forEach( function (num, index, myArray) {
        myArray[index] = num + 1;
    });
    return myArray;
  };
}

console.log(expandArray()());

The second set of parentheses after the call to expandArray() will invoke the closure and return the values you're seeking.

hcs
  • 321
  • 3
  • 14
0

Just fyi, you are doing something very similar to the memoization pattern.

To address your problem: as everyone else has already said, you return a function from expandArray. What you want is to return the closed array (after incrementing every element).

To do this, you can use something called immediately-invoked function expression in combination with arrow functions to simplify your code:

const expandArray = (() => {
  const myArray = [1, 1, 1];
  
  return () => {
    myArray.forEach((num, index) => {
      myArray[index] = num + 1;
    });
    
    return myArray;
  };
})();

console.log(expandArray());
console.log(expandArray());
console.log(expandArray());
FK82
  • 4,907
  • 4
  • 29
  • 42
0

There are a couple of things incorrect with your code.

  • you can't change the values of variables declared within const. In the case of Objects and Arrays, you aren't allowed to assign a new reference with a new Array or Object. We change the declarative operator to let instead of const.

  • myArray.map doesn't mutate myArray, it returns a new array based on the input from myArray and your passed in function that adds 1 to each value. We can fix this by assigning myArray.map to the already declared myArray. That is to say, we're overwriting the old Array with a new one. This is why const in the above bullet point won't work.

  • Your map function parameters are unnecessary The parameters for it that are most often used are the first two available, which is the item in the array and the index of that item. Since we're iterating over each number using map the function can simply return the item (declared as num in your code) plus 1. This will return a new array with your changed values. So we don't need the index at all..

  • When you return a function from a function you need to invoke both to get the second return value. When using a closure you need to keep a reference to the initial returned function. This is confusing but if you think of it as levels - in your expandArray function you have two levels. The function itself and the function you're returning. when you call expandArray() you're invoking the first level, and making the second level available to be invoked, this is why expandArray() returns the second function and expandArray()() will return the value from the second function. We save the returned function in a variable called add_to_array by setting it equal to expandArray(), and then we consistently invoke add_to_array to return the new Array with the changed values.

    • This is the most confusing part of closures, but what is happening is that the add_to_array variable is like a wedge in the function. It stops myArray from being deleted by the Browser because it requires the function to exist in the event that it needs to be invoked again. It's kind of like a bookmark in a book. For the story to make sense whenever you open it, you don't just tear out the pages before the bookmark. You keep the story intact because in five years when you come back to it you may need to read the previous pages at the bookmark to remember where you were. A closure works the same way. It can't remove the variables from the initial expandArray function call because add_to_array is a placeholder in the middle of it. The reference point keeps the book open. (for more info on closures you can check out this article here Destroying Buildings - A Guide to JavaScript Closures)

function expandArray() {
  let myArray = [1, 1, 1];

  return function () {
    myArray = myArray.map( function (num) {
       return num + 1;
    });
    return myArray;
  };
}

let add_to_array = expandArray();
console.log( add_to_array(),add_to_array(),add_to_array() );
zfrisch
  • 8,474
  • 1
  • 22
  • 34
0

Old post, but I still like to contribute. I came up with this solution, as I think you want add something to the array instead of incrementing the numbers.

function expandArray() {
    let myArray = [1, 1, 1];

    return function() {
        myArray.push(1)
        return myArray
    }
}

const array = expandArray();
const result = array();
console.log(result)
Imran Khan
  • 143
  • 2
  • 8
0

3years after this question was posted this lines of code works fine for me

function expandArray() {
    let myArray = [1, 1, 1];
    return function() {
        myArray.push(1);
        return myArray;
    };
}

let newArray = expandArray();
console.log(newArray());

Note this is my first contribution on stack overflow.

  • Question already answered. Please chech the answer with GREEN CHECKMARK. However, you may want to make your contribution better by using ES6/ES7 syntax. – Collins USHI Jun 04 '22 at 04:03
  • Please add supporting details to your answer to improve it. – Ethan Jun 06 '22 at 15:01