loading...

Writing Immutable and Functional JavaScript

jacobmgevans profile image Jacob Evans ・3 min read

Immutable Concepts and Techniques

Reasons for using immutable practices in JavaScript and React:

  • Lowers surface areas for bugs to be introduced.

    • one reason for this is simply, input data goes into function/method and predictable output occurs. Something that can be used to adhere to this is Pure Functions. Further examples of this can be examples of tacit programming applied to Higher Order Functions.
  • Creates a history of data & changes; that can be useful is following data flow or even something like debugging.

    • An example of a system utilizing a lot of these concepts would be something like Redux, it's methods of handling data changes creates a history of changes that can be stepped through.

Pure Functions:

  • No side effects; returns data without modifying any data outside its scope.
  • Predictably returns the same value (output) with the same input.

So the output is "predictable" so long as no X-Factor is introduced into the function; the only thing going into the function(func1) is input. If API data or data from another function (func2) is introduced that also changes depending on the input, you can no longer say for certain that the input for

const assignment:

  • const is great in preventing reassignment and redeclaration.
const variable = 'hello world'
try{
variable = 'Hello World!'
}catch(error){
console.log(error) // TypeError: invalid assignment to const 'variable'
}
Enter fullscreen mode Exit fullscreen mode
  • const isn't going to solve this alone, variable reassignment prevention is half the issue, probably even less than half of the mutation issue... But when it comes to the variables data it's certainly half.

There is awesome talk in ECMAScript proposals for a keyword being added that would be put on the right side of the assignment that would prevent mutation of the data. It would possibly look something like

const obj = immut { a: 1, b: 2 }

obj['a'] = 3 // Error Thrown

console.log(obj['a']) // 1
Enter fullscreen mode Exit fullscreen mode

Freezing Objects

  • shallow freezing objects to prevent accidental mutations of simple objects.
   const obj = { 
   zoo: 'animals'
   }
   Object.freeze(obj) 

   obj['zoo'] = 'noAnimals'
   console.log(obj['zoo']) // 'animals'

Enter fullscreen mode Exit fullscreen mode

Spread Operator

  • Utilizing the spread operator for Objects and Arrays is a great way to create shallow copies of the data from those sources then apply the copy of old data with new data in the new Object or Array.
const arr = [ 1, 2, 3, 4 ]

const newArr = [ ...arr, 'newData' ]

console.log(arr) // [ 1, 2, 3, 4 ]
console.log(newArr) // [ 1, 2, 3, 4, 'newData' ]
Enter fullscreen mode Exit fullscreen mode

Higher-Order Functions (HOF)

  • HOF's are a great tool but also adhere to immutability concepts. HOF will take in a function and return a function. If you are interested in furthering reading on HOF I suggest Eloquent JavaScript Chapter 5

Here is an example of utilizing HOF behavior to further adhere to immutability concepts in your code:

const arr = [ 1, 2, 3 ]

const newArr = arr.map(ele => ele * 2)

console.log(newArr) // [ 2, 4, 6 ]
console.log(arr) // [ 1, 2, 3 ]
Enter fullscreen mode Exit fullscreen mode

Tacit Programming (point-free)

So point-free style is a functional concept that can allow for abstractions. Now this can be overused which may lead to some gotcha's
or even just be confusing with the lack of argument naming...It even has a nickname from this overuse/misuse "pointless style." I feel if used properly its an abstraction of the arguments and implementation to a single function.

const arr = [ 1, 2, 3 ]

const addTwo = (ele) => ele + 2

const twoAddedPointFree = arr.map(addTwo)

console.log(twoAddedPointFree) // [ 3, 4, 5 ]

// You can even reuse it! 
const fourAdded = twoAddedPointFree.map(addTwo)
console.log(fourAdded) // [ 5, 6, 8 ] 
Enter fullscreen mode Exit fullscreen mode

Discussion

pic
Editor guide
Collapse
sebbdk profile image
Sebastian Vargr

This is great!
I wish everyone would read this. :)

I have been trying to subtlety nudge my other team members in this direction.
Especially in regards to pure functions.

Code usually becomes much more destructured, easier to refactor, re-use, etc.
When using concepts like these, in my experience. :)

Collapse
jacobmgevans profile image
Jacob Evans Author

Really glad you like it. I tried to not get overly complex and explain it as simply as I could... My joke is if I can explain it to my none technical friends and family then it's ready... This could still be better 😆😅

Thank you! 😁

Collapse
aroramayur profile image
aroramayur

const twoAddedPointFree = arr.map(addTwo) // [ 3, 4, 5]

Collapse
jacobmgevans profile image
Jacob Evans Author

🤣🤣🤣🤣 I math'd wrong 😅😅😅

Thank you! 😁

Collapse
aroramayur profile image
aroramayur

Welcome! You know it'd be great if you add some examples of the perils of mutating objects / data in an app, and how it can lead to debugging nightmare. Just a thought.