Chau Giang
Chau Giang

Reputation: 1554

Using pure function with Javascript object

Suppose I have a code like this:

function example() {
  const obj = {};
  for (let i = 0; i < 10; i++) {
    for (let j = 0; j< 10; j++) {
       if (obj[i] == undefined) {
         obj[i] = 0;
       }
       if (obj[j] == undefined) {
         obj[j] = 0;
       } else {
         obj[i] += i;
         obj[j] += j;
       }
    }
  }
}

Here you can see:

if (obj[i] == undefined) {
  obj[i] = 0;
}

I check if i not in obj I assign the key i inside obj with 0 else I do nothing, I do sample with j.

The code is duplicated and I do not want to repeat my self, it is bad practice so I make another function to apply for i and j like this:

function initObjWithValue(obj, keys) {
  for (const key of keys) {
    if (obj[key] === undefined) {
      obj[key] = 0;
    }
  }
}

The function is very easy to understand right? It has first parameter as an object and the second parameter is an array of keys to check. Now I can refactor my code like this:

function example() {
  const obj = {};
  for (let i = 0; i < 10; i++) {
    for (let j = 0; j< 10; j++) {
       initObjWithValue(obj, [i, j]);
       obj[i] += i;
       obj[j] += j;
    }
  }
}

The code is clearer but as you can see in my function initObjWithValue, it mutates obj and I think it is not good. Here is the quote from Wiki page:

In computer programming, a pure function is a function that has the following properties: Its return value is the same for the same arguments (no variation with local static variables, non-local variables, mutable reference arguments or input streams from I/O devices).

And I got stuck at this point, how can I do not repeat my self and I can achieve pure function in this case?

Upvotes: 4

Views: 425

Answers (2)

S K R
S K R

Reputation: 592

Instead of checking

(obj[i] == undefined)

write

(typeof obj[i] == undefined)

Upvotes: 0

Nick Parsons
Nick Parsons

Reputation: 50749

You could instead make initObjectWithValue return a new object, which you can then merge with your current obj. This way, all you're doing is reading from obj, and not mutating it within initObjectWithValue:

function initObjWithValue(obj, keys) {
  const tmp = {};
  for (const key of keys) {
    if (!(key in obj)) {
      tmp[key] = 0;
    }
  }
  return tmp;
}

function example() {
  const obj = {};
  for (let i = 0; i < 10; i++) {
    for (let j = 0; j< 10; j++) {
       Object.assign(obj, initObjWithValue(obj, [i, j])); // merge the return with current object
       obj[i] += i;
       obj[j] += j;
    }
  }
  return obj;
}

console.log(example());

Upvotes: 3

Related Questions