Say I have a function:
function linesReverser(lines) {
var localLines = lines.slice();
localLines[1].reverse();
return _.flatten(localLines);
}
And using it like so:
var input = [["Hello"],["Hello", "World"]["Attention", "Please"]];
var output1 = linesReverser(input); //["Hello", "World", "Hello", "Attention", "Please"]
var output2 = linesReverser(input); //["Hello", "Hello", "World", "Attention", "Please"]
Notice how the object reference is being shared. I am new to JS, but I thought copying the values would alleviate this issue (line.slice()), but it doesn't seem to work. Is this because of the nested arrays?
How can I non-destructively/immutably perform a reverse?
4 Answers 4
You can duplicate the array using ES6's spread operator, then destructively reverse the duplicate:
const arr1 = [1,2,3];
const arr2 = [...arr1].reverse();
// arr1 => [1,2,3]
// arr2 => [3,2,1]
1 Comment
reverse() is destructive.You're making a shallow copy of the lines array. To copy the nested arrays, you need to slice each one.
var localLines = lines.map(function(arr) {
return arr.slice();
});
The .map method will return a new Array of the return values, which are a slice of each nested Array.
FWIW, here's a shorter version that will work in modern browsers, though I'd probably stick with the first one.
var localLines = lines.map(Array.apply.bind(Array, null));
8 Comments
Array is just the new Array constructor. The .apply is the normal Function.prototype.apply. Using .bind(), we're binding the this value of .apply() to the Array function, and the first argument of .apply() to null, so the function returned will effectively do Array.apply(null, ...). Since the first argument passed by .map is each member of the lines array, the call becomes Array.apply(null, ["foo", "bar"]), which is the same as doing Array("foo", "bar"), giving us a new Array with those members..map(). In reality, each call to the callback will look more like Array.apply(null, ["foo", "bar"], 0, lines), where 0 is the current index, and lines is the original Array, but .apply() will ignore those extra args.A non-destructive approach to reverse an array in Javascript
ES6
var array = [1,2,3];
array.reduce((ary, ele) => {ary.unshift(ele); return ary}, []);
// => [3,2,1];
// array => [1,2,3];
ES5
array.reduce(function(obj, ele){
obj.unshift(ele);
return obj;
},[]);
Comments
You can safely (deep) copy a nested array with JSON.parse and JSON.stringify, therefore the reference is not shared. Then destructively reverse the duplicate:
let array1 = [[1, 3], [50, 1]];
let arrayCopy = JSON.parse(JSON.stringify(array1));
arrayCopy.reverse(); //[[50,1],[1,3]]
checkout cloning of arrays for more info