Movatterモバイル変換


[0]ホーム

URL:


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 offor(var x = ...)

Looping through a JavaScript array was traditionally done via afor() 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 likemap,forEach, andevery 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!

Request Metrics real user monitoring
Request Metrics real user monitoring
Request Metrics real user monitoring
Request Metrics real user monitoring

Recent Features

Incredible Demos

  • By
    5 More HTML5 APIs You Didn&#8217;t Know Existed

    TheHTML5 revolution has provided us some awesome JavaScript and HTML APIs.  Some are APIs we knew we've needed for years, others are cutting edge mobile and desktop helpers.  Regardless of API strength or purpose, anything to help us better do our job is a...

  • By
    Chris Coyier’s Favorite CodePen Demos IV

    Did you know you can triple-heart things on CodePen? We’ve had that little not-so-hidden feature forever. You can click that little heart button on any Pen (or Project, Collection, or Post) on CodePen to show the creator a little love, but you can click it again...

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 unfinishedforEach function for the reader to continue readinghttp://gadgets-code.com/javascript-array-prototype-foreach-method-usage

    • Nice follow-up, but I would really encourage you to useconsole.log() in such examples instead ofalert().

  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 alength variable within the for loop for the array iteration when one could just directly access the arraylength property, since in the example, thelength 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 thelength 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? Regularfor loop seems to be more efficient thanforEachhttp://jsperf.com/for-vs-foreach/37 .

  6. Danik

    I’m confused. I thought it was considered bad practice to useforEach 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

      usefor(index of myArray) instead ofin. It still has the side effect butof 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 rungetPage.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 usingforEach almost always leads to side effects…

Wrap your code in<pre></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!


[8]ページ先頭

©2009-2025 Movatter.jp