3

Am trying to add/remove elements from an array declared inside a function. I have been able to add or remove and access the updated array for the same.

For accessing the array I have used two different approaches.

  1. Have created an inner function which returns the array.
  2. Have returned the array from the main function and accessing the same using dot notation.

Here is my code:

function test() {
  let myArr = [];

  const getMyArr = () => myArr;

  const add = n => {
    myArr.push(n);
    return () => {
      myArr = myArr.filter(a => a !== n);
    };
  };


  return {
    myArr,
    getMyArr,
    add
  };
}

let myTestRun = test();


let remove3 = myTestRun.add(3);
let remove7 = myTestRun.add(7);
let remove8 = myTestRun.add(8);
console.log("myArr after insertion", myTestRun.myArr);
console.log("getMyArr() after insertion", myTestRun.getMyArr());
remove7();

console.log("myArr after removing", myTestRun.myArr); //still returns the old array without any modifications
console.log("getMyArr() after removing", myTestRun.getMyArr()); //returns the modified array. how? Why didn't it work before?

What I do not understand is why did myArr did not have any modifications and how come getMyArr() function has returned the updated value. I used to believe that both the myArr point to the same object. So, any modifications on the myArr should be reflected via both the approaches. Why am I wrong. What is the reason behind this different return values? Please explain.

Imran
  • 67
  • 6
  • Because `let myArr` and `return { myArr, ... }` no longer reference the same Array. The variable has been changed, the property on the returned object has not. and `getMyArr()` returns the value of the variable. – Thomas Jul 24 '19 at 08:52

3 Answers3

1

TL;DR: Because filter returns a new array.

The object returned by test and the local variable both are referencing the same array. Mutating the array (push, pop, splice etc) through either of the references will modify the array.

This is only up until the call to remove7(). The filter method returns a new array and myArr variable is now referencing this new array while myTestRun.myArr still references the old array created initially. If you log myTestRun.myArr === myTestRun.getMyArr() at every point, it will start returning false after remove7().

But, getMyArr() is still taking closure over the let myArr variable. So, it will always log whatever the variable is currently holding at that moment

Here are some similar questions which might make it clear:

adiga
  • 34,372
  • 9
  • 61
  • 83
  • _The variable let myArr and the myArr property of the object returned by the test function aren't referencing the same array any more._ How is that? Have I not returned `let myArr` which must be the same property returned from `test`? – Imran Jul 24 '19 at 12:44
  • @Imran Yes, you have. Updating `myTestRun.myArr` will update the `myArr` variable because both of these are pointing to the same array in memory. But, only until `remove7()` is called. `filter` returns a **new** array and `myArr` variable now points to a new memory location. While the `myTestRun.myArr` is till pointing to the old array. Updating one array will not affect the other array – adiga Jul 24 '19 at 16:06
  • I get it. Can you please edit your post and add it in your answer so that I could accept it. – Imran Jul 25 '19 at 07:49
  • @Imran updated the answer and added links to some additional questions which are very similar – adiga Jul 25 '19 at 11:48
1

You change the object reference of myArr, but you need the same object reference and for deleting, you could splice the unwanted elements.

function test() {
  let myArr = [];

  const getMyArr = () => myArr;

  const add = n => {
    myArr.push(n);
    return () => {
      var i = myArr.length;
      while (i--) if (myArr[i] === n) myArr.splice(i, 1);
    };
  };

  return { myArr, getMyArr, add };
}

let myTestRun = test();

let remove3 = myTestRun.add(3);
let remove7 = myTestRun.add(7);
let remove8 = myTestRun.add(8);
console.log("myArr after insertion", myTestRun.myArr);
console.log("getMyArr() after insertion", myTestRun.getMyArr());
remove7();

console.log("myArr after removing", myTestRun.myArr); //still returns the old array without any modifications
console.log("getMyArr() after removing", myTestRun.getMyArr()); //returns the modified array. how? Why didn't it work before?
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

Its better if you use

function test() {
  this.myArr = [];

  this.getMyArr = () => this.myArr;

  this.add = n => {
    this.myArr.push(n);
    return () => {
      this.myArr = this.myArr.filter(a => a !== n);
    };
  };
}

let myTestRun = new test();


let remove3 = myTestRun.add(3);
let remove7 = myTestRun.add(7);
let remove8 = myTestRun.add(8);
console.log("myArr after insertion", myTestRun.myArr);
console.log("getMyArr() after insertion", myTestRun.getMyArr());
remove7();

console.log("myArr after removing", myTestRun.myArr); //still returns the old array without any modifications
console.log("getMyArr() after removing", myTestRun.getMyArr());
Rahul Rana
  • 455
  • 2
  • 7