Saturday, July 18, 2020

Removing side effect

If the first statement modifies the variable that the second statement relies on, the code produces side effects or errors.

On functional programming, the original data must not be modified. You should not produce an output by modifying an input.

Hence (courtesy of freeCodeCamp), the following would produce side effect:

https://jsfiddle.net/c79nqfh5/2/
var Window = function(tabs) {
  this.tabs = tabs; // We keep a record of the array inside the object
};

// When you close a tab
Window.prototype.tabClose = function (index) {

  // Only change code below this line

  var tabsBeforeIndex = this.tabs.splice(0, index); // Get the tabs before the tab
  var tabsAfterIndex = this.tabs.splice(index + 1); // Get the tabs after the tab
  this.tabs = tabsBeforeIndex.concat(tabsAfterIndex); // Join them together


  // Only change code above this line

  return this;
};

var videoWindow = new Window(['Netflix', 'YouTube', 'Vimeo', 'Vine']); // Entertainment sites
console.log(videoWindow.tabClose(2).tabs); 

Output:
["Netflix", "YouTube"]

The output is incorrect, splice modifies the this.tabs state that tabsAfterIndex's expression relies on.

One way to solve the problem is to create a copy for this.tabs.

https://jsfiddle.net/c79nqfh5/3/
var tabsBeforeIndex = [...this.tabs].splice(0, index); // Get the tabs before the tab
    var tabsAfterIndex = [...this.tabs].splice(index + 1); // Get the tabs after the tab
    this.tabs = tabsBeforeIndex.concat(tabsAfterIndex); // Join them together

Output:
["Netflix", "YouTube", "Vine"]

But we should not do that if we can use a function that don't destroy the variable it operates on. In this case, we can use the slice function instead of splice.

https://jsfiddle.net/c79nqfh5/5/
var tabsBeforeIndex = this.tabs.slice(0, index);
  var tabsAfterIndex = this.tabs.slice(index + 1);
  this.tabs = tabsBeforeIndex.concat(tabsAfterIndex);

Output:
["Netflix", "YouTube", "Vine"]


If using ES6 or TypeScript, it can be improved further:
    this.tabs = [...this.tabs.slice(0, index), ...this.tabs.slice(index + 1)];

No comments:

Post a Comment