0

In the code below, I expected that the result of the 3 logs would be the same.

But they are not.

var m = (function () {
  var arr = [
    {a: 1, b: 2}, 
    {c: 3, d: 4}
  ];

  return {
    getArr: function () {
      return arr;
    }
  };
})();

var myArr = m.getArr();

console.log(myArr);

myArr.pop();

console.log(m.getArr());

What is the best way to ensure that the array is not passed as a reference?

Use return arr.map()?

TaoTao
  • 519
  • 1
  • 6
  • 14
  • You can use return arr.slice() - however be aware that this would only be a *shallow copy* and you can still run into issues. – Chris Cousins Sep 11 '18 at 19:23
  • 1
    In Javascript, all objects are effectively "passed by reference". (This isn't strictly true, but is an easy way to think of it.) Arrays are objects too, so this is why this happens. Note that primitive values (strings, numbers, booleans) are always "passed by value" instead. [This question](https://stackoverflow.com/questions/13104494/does-javascript-pass-by-reference) may be useful for further explanation – Robin Zigmond Sep 11 '18 at 19:37

2 Answers2

5

JSON.parse(JSON.stringify(arr)) will give you a deep copy of an object or array.

var m = (function () {
  var arr = [
    {a: 1, b: 2}, 
    {c: 3, d: 4}
  ];

  return {
    getArr: function () {
      return JSON.parse(JSON.stringify(arr));
    }
  };
})();

var myArr = m.getArr();

console.log(myArr);

myArr.pop();

console.log(m.getArr());
jmcgriz
  • 2,819
  • 1
  • 9
  • 11
  • 2
    While it works in most cases, a few things should definitely be brought to the attention of anyone using this method: **1.** It only works on JSON-serializable content (that is, your array and objects cannot contain functions/methods, nor `Infinity`, `null`, or `undefined`). **2.** It will convert `date` values to `string`. **3.** It is very inefficient. That said, if your array is small (relatively speaking) and consists of only primitives and/or objects that consist of only primitives (`string`/`number`/`boolean`), this method will work perfectly fine. – Tyler Roper Sep 11 '18 at 19:30
1
var m = (function () {
  var arr = [
    {a: 1, b: 2}, 
    {c: 3, d: 4}
  ];

  return {
    getArr: function () {
      return Array.from(arr);
    }
  };
})();

Ensure that the closure returns a copy of the arr.

  • This also returns a shallow copy, so if the array has multiple layers of depth, you could still run into problems using `Array.from` – jmcgriz Sep 11 '18 at 19:56