Skip to content

Instantly share code, notes, and snippets.

@gitmathub
Last active April 4, 2019 07:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gitmathub/fe9dab751a892f290444da511c5e75ab to your computer and use it in GitHub Desktop.
Save gitmathub/fe9dab751a892f290444da511c5e75ab to your computer and use it in GitHub Desktop.
Parameter Mutants

Mutate Parameters

It's common practice to mutate the parameters in JS. But there are some good reasons not do to. And ways how to do it better.

Docs

Call By Sharing

Javascript passes object to a function by Call by sharing. Can be said to pass by copy of reference.

JavaScript does not Call By Reference. However, JavaScript does not make copies of objects when they are passed or assigned. As such, it is the same object with a different name - changes made to the object (from any name) affect said object.

Examples

Outside Object Changed When Modified in Function

The outside object is changed by a function.

const object = {
  a: "hello"
}

function modify(o) {
  o.a += " world"
}

modify(object)
console.log(object.a)
//prints "hello world"

Run code: https://repl.it/@replmat/parameter-changes-visible-outside

Outside Object NOT Changed When Re-Assigned in Function

Not that the object is not modified by += like in the example above but fully re-assigned with a new value. The reason is, that the copy of a reference is another name for the reference. That name is kinda "hi-jacked" and assigned to a new value.

var obj = {
  a: "hello"
};

function modify(o) {
  o = {
    a: "hello world"
  };
}

modify(obj);
console.log(obj.a); //prints just "hello"

Run code: https://repl.it/@replmat/parameter-hi-jacked

Discussion

Functions modify objects

Functions modify objects and objects are passed to the function as parameter.

Thesis: Functions use and modify objects. If you are passing an object to a function, then you would expect that the function does something with the object and might change it. So it is intentional, that the outside object gets modified. That the programm intentionally changes the object might become more visible, if setters are used. In TypeScript it's not always easy to identiyfy setters. See some examples below.

class Person {
  name?: string
  age?: number
  _weight?: number

  constructor(anyObject?: any) {
    if (anyObject) {
      Object.assign(this, anyObject)
    }
  }

  // setter in flavor a
  set weight(weight: any) {
    this._weight = weight
  }

  // setter in flavor b
  setWeight(weight: any) {
    this._weight = weight
  }
}

const paul: Person = new Person({name: "paul"})
console.log(paul) // Person { name: 'paul' }

//
// mutate parameter/ object directly
//
function evaluateAge(person: Person){
  person.age = 5
}
evaluateAge(paul)
console.log(paul) // Person { name: 'paul', age: 5 }

//
// change object with setter a
//
function calculateWeight(person: Person){
  // calculate something and finally set the weight
  person.weight = 80
}
calculateWeight(paul)
console.log(paul) // Person { name: 'paul', age: 5, _weight: 80 }

//
// change object with setter b
//
function updateWeight(person: Person, kilos: number){
  person.setWeight(kilos)
}
updateWeight(paul, 70)
console.log(paul) // Person { name: 'paul', age: 5, _weight: 70 }

Run code: https://repl.it/@replmat/Object-setter About setters and getter in Typescript see here: Documenation Classes

Functional-style programming promotes the idea that a program is about transforming data through functions, and that mutation should be avoided

Pure Functions

If you'd like functions to be pure, then do not change the value of the input or any data that exists outside the function's scope.

This makes the function we write much easier to test. As it does not change the state of any variable, we are guaranteed to get the same output every time we run the function with the same input.

function foo (_bar) {
  var bar = _.clone(_bar) // lodash lib
  bar.k1 = "bananas"
  return bar
}

https://stackoverflow.com/questions/28792326/functional-style-javascript-good-practice-to-avoid-argument-mutation https://stackabuse.com/functional-programming-in-python/

Using VueX

  • decide what your objects and program stats are and put them into the store
  • use strickt in order to get warnings if mutatins happens outside the mutations.js
  • if you need to transform a vuex object, then use _.cloneDeep() from lodash or similar expressions to make a real copy of your object before you modify it. A typical use case would be: the object should get stored in the database and the properties need mappig.

Values or Objects as parameters?

Options

  • always use values
  • always use objects
  • always use values but objects if the parameters are optional
  • use "class" objects if paramters get complex

Pro values

  1. paramaters don't need to be named
greet(name) {
  console.log("Hello ", name)
}
greet("Paul")
  1. you can rename the parameters, depending of the context
function markdownToJson(markdown) { /* implementation */ }
const message = "I **love** you"
markdownToJson(message)
  1. very common approach
  2. low overhead

Pro objects

  • function call names parameter explicitly. This can bring clearity
  • order of parameters doesn't matter
  • if parameter list gets too long
function getRegisteredUsers ({ fields, include, fromDate, toDate }) { /* implementation */ }
getRegisteredUsers({
  fields: ['firstName', 'lastName', 'email'],
  include: ['invitedUsers'],
  fromDate: '2016-09-26',
  toDate: '2016-12-13'
})

futher links to study

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment