Pure Array Modifications: Plain JavaScript vs. Modern JavaScript

Glenn Stovall on September 25, 2018

The post Pure Array Modifications: Plain JavaScript vs. Modern JavaScript appeared first on Glenn Stovall - Growth Engineer. When working with R... [Read Full]
markdown guide
 

Nice article! Just have a few comments:

The examples for #4 and #5 look like they're switched.

For #6, the ++ in arr.slice(i++) doesn't actually do anything. The original value of i will be returned to slice prior to incrementing, and even if it did, the resulting array would be inaccurate. I would just stick with:

const pureInsert = (arr, el, i) => [...arr.slice(0, i), el, ...arr.slice(i)]

For #7, your pureReplace method works great but can be cleaned up to look more consistent with #6:

const pureReplace = (arr, el, i) => [...arr.slice(0, i), el, ...arr.slice(++i)]

pureReplace([1,2,3,4,5], 'foo', 2)   // [1,2,'foo',4,5]

Consistency aside, the outright return will also avoid opening up an unnecessary closure into your function. Defining an array via let copy and handing it off to another scope will delay garbage collection of your functional context, as any mutations to the array will need to reference the original copy variable. (I wouldn't be making such a fuss if you just returned a primitive, pass-by-value type!)

 

Thanks for the great feedback! I've made the suggested changes to the article

 

Isn't the ++ operator changing the parameter value?

 

It will only change the parameter after the line. For example:

let num = 5
console.log(num++)  // still logs 5!
console.log(num)    // logs 6

Notice how the number stays at 5 on the second line, and the ++ doesn't take into effect until the next line. To increment in place, you'd have to move the ++ to the left of the operand:

let num = 5
console.log(++num)  // logs 6
console.log(num)    // logs 6

Knowing this, the ++ in example #6 of the article doesn't actually do anything:

const pureInsert1 = (arr, el, i) => [...arr.slice(0,i), el, ...arr.slice(i++)]
const pureInsert2 = (arr, el, i) => [...arr.slice(0,i), el, ...arr.slice(i)]

const nums = [1,2,4,5]

pureInsert1(nums, 3, 2)  // [ 1, 2, 3, 4, 5 ]
pureInsert2(nums, 3, 2)  // [ 1, 2, 3, 4, 5 ]

If anything the ++ is confusing because it looks as if the user is intending to increment i. If the parameter actually changed, we would get a defective insert:

const pureInsert = (arr, el, i) => [...arr.slice(0,i), el, ...arr.slice(++i)]

const nums = [1,2,4,5]

pureInsert(nums, 3, 2)  // [ 1, 2, 3, 5 ]

I understend How the ++ operator Works, but I believe by changing a parameter value, the function will no longer be a pure function. I think that the ++ operator Will result in a side effect to the third parameter.

Nope, the function will remain pure because primitive types in JavaScript are passed by value. This means when i is passed in as an argument, pureInsert creates a brand new functional context that contains its own copy of i as opposed to referencing the original variable that was passed in. Since the function cannot mutate the original variable, purity is maintained.

let myNum = 1

const attemptMutation = (i) => {
  console.log(++i)
}

console.log(myNum)      // logs 1
attemptMutation(myNum)  // logs 2
console.log(myNum)      // still logs 1

If you really wanted to make the ++ operator "impure", you could use a higher-order function.

code of conduct - report abuse