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
    9 Mind-Blowing WebGL Demos

    As much as developers now loathe Flash, we're still playing a bit of catch up to natively duplicate the animation capabilities that Adobe's old technology provided us.  Of course we have canvas, an awesome technology, one which I highlighted 9 mind-blowing demos.  Another technology available...

  • By
    5 Awesome New Mozilla Technologies You&#8217;ve Never Heard Of

    My trip to Mozilla Summit 2013 was incredible.  I've spent so much time focusing on my project that I had lost sight of all of the great work Mozillians were putting out.  MozSummit provided the perfect reminder of how brilliant my colleagues are and how much...

Incredible Demos

  • By
    Disable Autocomplete, Autocapitalize, and Autocorrect

    Mobile and desktop browser vendors do their best to help us not look like idiots by providing us autocomplete, autocorrect, and autocapitalize features.  Unfortunately these features can sometimes get in the way;  we don't always want or need the help they provide.  Luckily most browsers allow...

  • By
    dat.gui:  Exceptional JavaScript Interface Controller

    We all love trusted JavaScript frameworks like MooTools, jQuery, and Dojo, but there's a big push toward using focused micro-frameworks for smaller purposes. Of course, there are positives and negatives to using them.  Positives include smaller JS footprint (especially good for mobile) and less cruft, negatives...

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!