Preventing Side Effects in JavaScript

By  on  

JavaScript is very dynamic these days but I still see a lot of legacy code, whether it be for optimal backward compatibility or simply that the code hasn't been maintained.  One of the practices that makes me cringe is coding that creates unwanted side effects.  What's a side effect?  A piece of code whereby a variable is created and available throughout a scope when it doesn't need to be.  Let me show you a few examples and how to avoid these unwanted side effects.

Array.prototype.forEach() instead of for(var x = ...)

Looping through a JavaScript array was traditionally done via a for() loop:

var myArray = [1, 2, 3];

for(var x=0, length = myArray.length; x < length; x++) {
	// ...
}

// "x" and "length" are side effects

The side effect of this pattern is at minimum the running index, if not the length as well -- they are available within the entire scope.  Array prototype methods like map, forEach, and every allow the developer to avoid these side effects:

[1, 2, 3].forEach(function(item, index, array) {
	// No side effects! :)
});

No "utility" variables need to be created for the looping, thus avoiding side effects. This is called "functional" programming.

Self-Executing Functions

If you haven't read Hiding Your Privates with JavaScript, and you don't know how to keep private variables in JavaScript, take a few minutes to read it.  The same pattern provided in that post allows you to avoid side effects via self-executing functions:

// Example from MooTools source...

Browser.Request = (function(){

	var XMLHTTP = function(){
		return new XMLHttpRequest();
	};

	var MSXML2 = function(){
		return new ActiveXObject('MSXML2.XMLHTTP');
	};

	var MSXML = function(){
		return new ActiveXObject('Microsoft.XMLHTTP');
	};

	return Function.attempt(function(){
		XMLHTTP();
		return XMLHTTP;
	}, function(){
		MSXML2();
		return MSXML2;
	}, function(){
		MSXML();
		return MSXML;
	});

})();

// The three vars are stuck in the self-executing function, they don't "leak" out

The gist is that you can do loads of processing within the self-executing function (a new scope) without allowing variables leaking out -- the only item returned or leaked is the desired return value.

Tightening up your code includes avoiding side effects and JavaScript makes it easy if you follow these basic practices!

Recent Features

  • By
    JavaScript Promise API

    While synchronous code is easier to follow and debug, async is generally better for performance and flexibility. Why "hold up the show" when you can trigger numerous requests at once and then handle them when each is ready?  Promises are becoming a big part of the JavaScript world...

  • By
    Being a Dev Dad

    I get asked loads of questions every day but I'm always surprised that they're rarely questions about code or even tech -- many of the questions I get are more about non-dev stuff like what my office is like, what software I use, and oftentimes...

Incredible Demos

  • By
    Introducing MooTools LinkAlert

    One of my favorite Firefox plugins is called LinkAlert. LinkAlert shows the user an icon when they hover over a special link, like a link to a Microsoft Word DOC or a PDF file. I love that warning because I hate the surprise...

  • By
    MooTools Link Fading

    We all know that we can set a different link color (among other properties) on the hover event, but why not show a little bit more dynamism by making the original color fade to the next? Using MooTools 1.2, you can achieve that effect. The MooTools...

Discussion

  1. This is a good start, but the philosophy of side-effect free programming runs much deeper, and forms the foundation of the functional programming paradigm. To help people understand the philosophical underpinnings, I wrote “The Dao of Immutability”: https://medium.com/javascript-scene/the-dao-of-immutability-9f91a70c88cd

  2. Very informative article, david. I have touched up the unfinished forEach function for the reader to continue reading http://gadgets-code.com/javascript-array-prototype-foreach-method-usage

    • Nice follow-up, but I would really encourage you to use console.log() in such examples instead of alert().

  3. Island

    Alright, thanks for the advice :)

  4. Radek

    Hi, thanks for the article. I hope you continue writing on the topic.

    I think the utility variables should not be an issue as long as they do not leak out from methods and variables are always initialized before usage. What bothers me more is the length variable which is global.

    • I’m curious as to why one would define a length variable within the for loop for the array iteration when one could just directly access the array length property, since in the example, the length value is never modified.

    • Andreas

      Because computing the length could be expensive. You would do it over and over instead of accessing a variable which is cheaper.

    • :( Javascript doesn’t cache that length computation behind the scenes I guess?

    • Radek

      You are right – in this example we would get away with using the length property. In case of other languages or data structures it is a good habit to calculate the iteration count beforehand.

      Btw. I misread the semicolons – length variable is not global.

  5. Anna

    What about performance though? Regular for loop seems to be more efficient than forEachhttp://jsperf.com/for-vs-foreach/37 .

  6. Danik

    I’m confused. I thought it was considered bad practice to use forEach on an array?

  7. What about this one and is there any side effects?

     var myArray = [1, 2, 3];
    for(index in myArray) {
    	// ...
    }
    • Drew

      the for construct doesn’t protect or define index in that case: this is implicitly creating var index, which then leaks. Just run that code in the console and check what “index” is afterwards. It’ll have a value, and probably not even one you’d expect.

    • Adam

      use for(index of myArray) instead of in. It still has the side effect but of does not loop through all properties of the array.

  8. I found this article when I was looking for how to manage side-effects/side-causes in JavaScript a few months ago. Recently I have been experimenting with creating Intentions in JavaScript. They act like promises but build a description of what should be done that is only executed when explicitly called. It might be of interest for other people showing up here. https://github.com/CrowdHailer/intention.js

    e.g.

    var getPage = new HTTPAction(function (fetch) {
      return fetch('/users.html').then(function (response) {
        return response.text()
      })
    })
    
    // No externam call is made untill the action is run
    getPage.run(window.fetch).then(function (body) {
      console.log(body)
    })
    
  9. Adam

    to David W. using the anonymous icon for guest user is deceiving of an experienced user. ;)

  10. Worker11811

    In my experience using forEach almost always leads to side effects…

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!