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
    Chris Coyier&#8217;s Favorite CodePen Demos

    David asked me if I'd be up for a guest post picking out some of my favorite Pens from CodePen. A daunting task! There are so many! I managed to pick a few though that have blown me away over the past few months. If you...

  • By
    LightFace:  Facebook Lightbox for MooTools

    One of the web components I've always loved has been Facebook's modal dialog.  This "lightbox" isn't like others:  no dark overlay, no obnoxious animating to size, and it doesn't try to do "too much."  With Facebook's dialog in mind, I've created LightFace:  a Facebook lightbox...

Incredible Demos

  • By
    Animated Progress Bars Using MooTools: dwProgressBar

    I love progress bars. It's important that I know roughly what percentage of a task is complete. I've created a highly customizable MooTools progress bar class that animates to the desired percentage. The Moo-Generated XHTML This DIV structure is extremely simple and can be controlled...

  • By
    Spoiler Prevention with CSS Filters

    No one likes a spoiler.  Whether it be an image from an upcoming film or the result of a football match you DVR'd, sometimes you just don't want to know.  As a possible provider of spoiler content, some sites may choose to warn users ahead...

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!