Improve Your Code with Smart JavaScript Techniques and Patterns

Smart JavaScript Techniques

In this article we’re going to cover some common, and not so common smart JavaScript techniques and patterns to improve your code in both size and beauty. To follow along with this tutorial it’s important that you have a good understanding of functional programming in JS and regular expressions.

Smart JavaScript Techniques

Smart JavaScript Techniques and Patterns

If you already know about this and that, call, apply, bind and prototypes, then you’re ready to start. Otherwise here’s a few articles to get you started before we begin:

Long Multiple Conditions

This first tip might not be obvious but it’ll help you reduce those long if statements. The idea is to replace logical operators and comparisons with a simple regex test:

If you see yourself doing this:

if (val == 'a' || val == 'b' || val == 'c')

This can be done with regex shorter and nicer:

if (/a|b|c/.test(val))

Another case that you might have to deal with is multiple variables and the AND logical operator, for example:

if (a == 1 && b == 2 && c == 3 && d == 4 && e == 5)

When you have a very long list of variables where you want to compare their values you can create an array with the expected values and another array with the given variables and use the every method to loop and compare. every returns true only if all conditions are met.

var vars = [a,b,c,d,e],
    vals = [1,2,3,4,5];

if (vals.every(function(val,i){ return vars[i] == val }))

This could be abstracted to be reused:

function isTrue(vars, vals) {
  return vals.every(function(val,i){ return vars[i] == val });
}

if (isTrue([a,b,c,d,e], [1,2,3,4,5]))

For the OR logical operator case you’d use the some method which returns true if at least one condition is met. But it’s less common to find long OR patterns like that, it would typically be mixed with ANDs:

if (a == 1 && b == 2 || c == 3 && d == 4 || e == 5 && f == 6)

In this case the logical operator approach seems smart enough.

Text Manipulation

JavaScript’s string tools are quite limited compared to other languages. Consider the case where we have some paragraphs separated by periods and we want to capitalize the first letter of every one of them. Using loops and some string methods we’d do something like this:

var str = 'the sky is blue. apples are green.';

var para = str.split('.'), // get array of paragraphs
    i = 0, len = para.length, p;

for (; i < len; i++) {
  p = para[i].trim(); // make sure there's no additional whitespace
  para[i] = p.substr(0,1).toUpperCase() + p.substr(1, p.length);
}

para = para.join('. ').trim(); // put everything back together

console.log(para);
//^ "The sky is blue. Apples are green."

While this works fine, the obvious smart approach here is to use regular expressions, and all of this becomes incredibly beautiful and concise:

str = str.replace(/([^.]+\.\s?)/g, function(_, para) {
  return para.replace(/^\w/, function(first) {
    return first.toUpperCase();
  });
});

console.log(str);
// ^ "The sky is blue. Apples are green."

Consider another usual case where you want to extract all telephone numbers from some text. Let’s suppose in our string all telephone numbers have the prefix tel:, that way we can grab only telephone numbers and not other irrelevant numbers that the string may contain. It’s evident that regex is the best tool for this task and since there might be multiple telephone numbers we’re going to use a global regex. We could try using match first:

var str = 'Jerry, 26 years old, tel: 555-000-0000. Joy, 19 years old, tel:777-000-0000.';
var numbers = str.match(/tel:\s?([\d-]+)/g);
console.log(numbers); //=> ["tel: 555-000-0000", "tel:777-000-0000"]

But as you can see the output still contains tel: even tough we’re using a capturing group to only get the number. The problem is that match doesn’t capture groups in global regex, for that reason you need to use exec and a confusing while loop pattern that you might have seen before:

var re = /tel:\s?([\d-]+)/g,
    numbers = [], match;

while (match = re.exec(str)) {
  numbers.push(match[1]);
}

console.log(numbers); //=> ["555-000-0000", "777-000-0000"]

That’s usually the code necessary to extract global matches, but it’s not the only option. The replace method takes a function where the first argument is the string itself and the following arguments point to the different capturing groups. The last two arguments are trivial in this case. Knowing this we can make our code smarter:

var numbers = [];
str.replace(/tel:\s?([\d\-]+)/g, function(_, number) {
  numbers.push(number);
});

console.log(numbers); //=> ["555-000-0000", "777-000-0000"] 

As long as you remeber that replace is being used only for the purpose of looping the code becomes obvious, less confusing. We could even make this available to all strings as a new gmatch method:

String.prototype.gmatch = function(regex) {
  var result = [];
  this.replace(regex, function() {
    // extract matches by removing arguments we don't need
    var matches = [].slice.call(arguments, 1).slice(0,-2);
    result.push.apply(result, matches);
  });
  return result;
};

console.log(str.gmatch(/tel:\s?([\d\-]+)/g)) //=> ["555-000-0000", "777-000-0000"]

Now that looks much nicer, proper global match right on the spot.

Generating HTML Markup

A very common case when dealing with HTML strings is creating lists, like li, td, option and others. Typically you’d loop to do this:

var values = ['one', 'two', 'three', 'four', 'five'];

var html = '';
for (var i = 0; i < values.length; i++) {
  html += '<td>'+ values[i] +'</td>';
}

That seems efficient enough but for loops are ugly. We can make this code smarter by using the join array method:

var html = '<td>'+ values.join('</td><td>') +'</td>';

That looks better, but what if we need the index?. In that case the map method can be used in combination with join.

var html = values.map(function(text, i) {
  return '<td>'+ text +': '+ i +'</td>'
}).join('');

When this gets more complex though, we end up having to write many loops with disconnected HTML pieces so everything becomes a little bit of a mess. The solution to this problem is to use templates. There are many templating libraries out there and this is no replacement, but knowing what we know so far we could create a very simple templating helper:

function template(arr, html) {
  return arr.map(function(obj) {
    return html.join('').replace(
      /#\{(\w+)\}/g,
      function(_, match) { return obj[match]; }
    );
  }).join('');
}

It can be used like this:

var people = [
  { name: 'John', age: 25, status: 'Single' },
  { name: 'Bill', age: 23, status: 'Married' },
  { name: 'Mika', age: 17, status: 'Single' }
];

var html = template(people, [
  '<div>',
    '<h1>Name: #{name}</h1>',
    '<h2>Age: #{age}, Status: #{status}</h2>',
  '</div>'
]);

console.log(html);
// ^
// "<div><h1>Name: John</h1><h2>Age: 25, Status: Single</h2></div>\
// <div><h1>Name: Bill</h1><h2>Age: 23, Status: Married</h2></div>\
// <div><h1>Name: Mika</h1><h2>Age: 17, Status: Single</h2></div>"

With this helper you can see how easy it is now to create content in a clear, structured manner.

Going all Functional

JavaScript is a multi-paradigm language with impressive functional programming (FP) features that often make your code more concise and compact as you’ve seen in previous examples.

All latest browsers, including IE9, have support for EcmaScript5 array and object methods. Whenever there’s a for or for..in loop there is an alternative solution with one of these methods.

One advantage of functional looping that might not seem so obvious is that it creates a new scope. This is particularly useful when running asynchronous code inside a loop. Imagine this case:

var arr = ['a','b','c'];
for (var i = 0; i < arr.length; i++) {
  setTimeout(function() { console.log(arr[i] +':'+ i); }, i * 1000);
}

The intention here is to log a:0..b:1..c:2 with one second in between but the result ends up being undefined:3..undefined:3..undefined:3. The typical workaround is to create a new scope:

for (var i = 1; i <= 3; i++) {
  setTimeout((function(i) { console.log(arr[i] +':'+ i); }(i)), i * 1000);
}

Now the output is as expected but it looks a bit confusing. Since a forEach loop already creates a new scope things become simpler:

arr.forEach(function(v, i) {
  setTimeout(function() { console.log(v +':'+ i); }, i * 1000);
});

When working with large amounts of data using a functional approach is a great way to improve readability. Take some data like the following:

var users = [
  { 
    name: 'Fred', 
    age: 25, 
    job: 'Developer', 
    membership: 'Gold'
  },
  {
    name: 'John', 
    age: 28, 
    job: 'Cook', 
    membership: 'Platinum'
  },
  {
    name: 'Zoe', 
    age: 32, 
    job: 'Make-up artist', 
    membership: 'Silver'
  },
  {
    name: 'Louise', 
    age: 35, 
    job: 'Cook', 
    membership: 'Silver'
  }
];

With array methods you could simply filter users by any criteria:

var over30 = users.filter(function(user) {
  return user.age >= 30;
});

var cooks = users.filter(function(user) {
  return user.job == 'Cook';
});

This code works and looks good enough but it seems like we’ll have to repeat this pattern again and again to extract information from our object. In order to make our code smarter this time around we’re going to make use of prototypes and some functional patterns we’ve covered before to create a very small DSL to handle our data.

What we want to able to do is something like this:

var over30 = users.where('age').is('>=30');
var cooks = users.where('job').is('Cook');

First let’s take a look at the code and then will see what’s possible with this little library. It can be challenging to follow the code if you don’t have a deep understanding of functional programming in JavaScript but hopefully the comments will make it a little bit clearer.

// An Immediately Invoked Function Expression (IIFE)
// to prevent us from leaking variables to the global scope
(function(win) {

  // Main constructor for the MyStorage object
  function MyStorage(data) {
    this.data = data; // the array containing our data
    this.length = this.data.length; // just a shortcut
  }

  // Shortcut to create new instances of MyStorage
  function stored(data) {
    return new MyStorage(data);
  }

  // Very basic object extender
  function _extend(obj, target) {
    for (var o in obj) target[o] = obj[o];
    return target;
  }

  MyStorage.prototype = {

    // Private:

    // Update data and return a new instance.
    // We need to clone the objects otherwise
    // they would be passed as reference
    _new: function(result) {
      result = result.map(function(o) { return _extend(o, {}); });
      this.length = this.data.length;
      return stored(result);
    },

    // Filter the current data property with a function.
    // The property is passed as parameter into the 'fn' callback
    _filter: function(fn) {
      return this._new(this.data.filter(function(user, i) {
        return fn.call(this, user[this.prop], i);
      }.bind(this)));
    },

    // Public:

    // Get an array with a specific prop from each object
    // or return the data collection otherwise
    get: function(prop) {
      if (prop) return this.map(function() { return this[prop]; });
      return this.data;
    },

    // Set the property to filter or compare to
    where: function(prop) { 
      return this.prop = prop, this; 
    },

    // A shortcut for semantics
    and: function(prop) { return this.where(prop); },

    // Compare the current property to a given condition
    is: function(condition) {
      // Filter by regular expression or string/number
      var regex = condition instanceof RegExp ? condition :
        new RegExp('^'+ condition +'$');

      // Extracts the symbol in cases like '>50' and '<=10'.
      // 'null' and '0' are given as default values if
      // the string doesn't contain a symbol
      var symbol = (/^([<>=%]+)([\d.]+)/.exec(condition) || [0,null,0]);

      // Process the symbol if present
      if (symbol[1]) return this[symbol[1]](+symbol[2]);

      return this._filter(function(prop) { 
        return regex.test(prop); 
      });
    },

    '>': function(v) {
      return this._filter(function(p) { return p > v; });
    },

    '>=': function(v) {
      return this._filter(function(p) { return p >= v; });
    },

    '<': function(v) {
      return this._filter(function(p) { return p < v; });
    },

    '<=': function(v) {
      return this._filter(function(p) { return p <= v; });
    },

    '%': function(v) {
      return this._filter(function(p) { return p % v === 0; });
    },

    // Sort collection by the given function
    // and return a new Templee instance
    sort: function(fn) {
      return this._new(this.data.sort(function() {
        return fn.apply(this, [].slice.call(arguments));
      }.bind(this)));
    },

    // Filter the collection by index
    eq: function(index) {
      return this._new(this.data[index]);
    }

  };

  // Curry most native methods
  'forEach map slice every some reduce'.split(' ').forEach(function(method) {
    MyStorage.prototype[method] = function(fn) {
      return this.get()[method](function() { 
        return fn.apply(arguments[0], [].slice.call(arguments)); 
      }.bind(this));
    };
  });

  win.stored = stored; // expose constructor to user

}(window));

Using Storage is very similar to how you’d use jQuery, very intuitive:

stored(users)
  .where('age').is('>30')
  .and('job').is('Cook').forEach(function(user) {
    console.log(user.name); // Louise
  });

Imagine the possibilities of combining this with the HTML templating system we created before:

var movies = [
  { title: 'Spiderman', score: 7, gross: 90e6 },
  { title: 'Aliens vs Predators', score: 5 , gross: 50e6 },
  { title: 'American Beauty', score: 9.5 , gross: 140e6 },
  { title: '500 Days of Summer', score: 8.5 , gross: 75e6 },
  { title: 'Drive', score: 7.5 , gross: 120e6 },
  { title: '127 Hours', score: 9 , gross: 78e6 }
];

var myMovies = stored(movies);

var featured = template(myMovies.where('score').is('>=8').get(), [
  '<div class="featured-movie">',
    '<h2>#{title}</h2>',
    '<h3>Score: #{score}, Gross: #{gross}</h3>',
  '</div>'
]);

var bigGross = template(myMovies.where('gross').is('>80000000').get(), [
  '<ul class="big-gross-movies">',
    '<li>#{title} <span class="gross">#{gross}</span></li>',
  '</ul>'
]);

$('body').append([
  '<h1>Featured Movies:</h1>'+ featured,
  '<h1>Big Gross Movies:</h1>'+ bigGross,
].join(''));

Other more complex examples are also possible:

// Get all movie titles that start by number
myMovies.where('title').is(/^\d/).get('title'); //=> ["127 Hours", "500 Days of Summer"]

// Chaining
myMovies.where('gross').is('>100000000')
  .and('score').is('>9').get('title') //=> ["American Beauty"]

And of course you can chain all those useful native array methods, forEach, map, slice, every, some, reduce:

// Will log one movie title per second
myMovies.forEach(function() {
  setTimeout(function() { console.log(this.title) }.bind(this), 1000);
});

You can play with this nice demo putting these snippets together: JS Bin

Conclusion

By using functional techniques we can achieve very clean abstracted modular code. Libraries like jQuery and Zepto make use of some of these patterns to make their code smarter, better.

In terms of support, since EcmaScript5 is very well supported nowadays, all of these snippets should work in IE9 and all other modern browsers. To support older browsers you might want to use polyfills to add that functionality.

Hopefully you got some new fresh ideas to try out and make your code smarter and more efficient. Leave me a comment below if you have any questions.

Cedric Ruiz is a freelance graphic and web designer/developer with a passion for computers and technology. He actually studied 3D animation but took a totally different path. He needs to learn something new everyday and he loves challenges and teaching people new skills.

Comments

    • felix,
    • February 22, 2013
    / Reply

    FP going all functional ?

    but wait, inside your function you are accessing an array that is not passed into the function and you are printing to the console. this is not FP in the least.

    functional programming is not “functions”

      • Cedric Ruiz,
      • February 22, 2013
      / Reply

      What piece of code are you referring to?

      • Cedric Ruiz,
      • February 22, 2013
      / Reply

      Oh, I think I see what you mean. In “Going all functional” the first example is just a typical `for` loop to pose a problem that can be solved with a functional style by using `forEach`.

      –“functional programming is not “functions”
      JS is multi-paradigm language so it really depends on how you define “functional programming”.
      Tale a look at http://stackoverflow.com/questions/3962604/is-javascript-a-functional-programming-language

  1. / Reply

    Very neat and informative. The simple templating function will be useful for my next project. Thanks! :)

    • Cedric Ruiz,
    • February 22, 2013
    / Reply

    Just a quick note on tip number one. `if (/a|b|c/.test(val))` is the simplest example but it will fail with strings that contain other strings being tested. If you find this case you should use this regex instead: `/^a|b|c$/.test(val)`.

  2. / Reply

    While I agree that using “if (/a|b|c/.test(val))” is shorter and in some ways nicer, “if (val == ‘a’ || val == ‘b’ || val == ‘c’)” is much more readable and understandable.

    From a maintainability point of view, and considering the number of web developers who are not fluent in regular expressions, I’m not convinced there is really any benefit to using the regular expression.

    In my experience, the simplest solution is preferred. There’s less chance of error, less chance of developers misunderstanding what the code is doing, and it’s just easier to read.

    1. / Reply

      I strongly agree with you. By the way from a performance point of view the first snippet will be much faster, especially since using litteral regular expressions.

      The patterns are using functions to make it smarter but so lesser readable. Most of them are growing the execution stack lenght and the number of objects in the heap memory.

      So my opinion is to use it when it really make sense.

        • Cedric Ruiz,
        • February 25, 2013
        / Reply

        I agree that for short `if` statements it makes no sense, but for multi-line long and confusing conditionals it does improve readability, at least in my experience.

        Plus regex are fast! And the `every` loop is fast as well. The performance difference is negligible. I think is worse to pre-optimize than to use whatever is best for the job.

        I have to agree that “number of web developers who are not fluent in regular expressions” makes it less tempting to use in larger code bases.

        • Cedric Ruiz,
        • February 25, 2013
        / Reply

        Here’s the performance tests:

        http://jsperf.com/condition-vs-regex-every-loop
        http://jsperf.com/condition-vs-regex

        As you can see, not much of a difference, at least on these generic tests.

        1. / Reply

          I modified your test, because :
          /a|b|c/.test(‘val’)===true

          And added some sugar like 2 conditions, one evaluating to true and the other to false..

          I also removed the console.log instruction that is slow and messes the tests.

          http://jsperf.com/condition-vs-regexp-vs-every-vs-indexof

          I think a better way to do that is [‘a’,’b’,’c’].indexOf(val)!==-1 if performance does not matter to you. It is more readable.

  3. / Reply

    i want to implement moving picture image by using java script concept in my blog but i am not able to find code that i can edit . i am beginner in java script .Please help me.

    • axel,
    • February 24, 2013
    / Reply

    I’m surprised to see articles selling techniques for “improved” JavaScript.
    You should define what you understand as an “improved” JavaScript.
    Is it “improved” performance-wise ? or in terms of readability and mantainability ?

    Consider the following snipet you take as an example :

    var str = ‘the sky is blue. apples are green.’;

    var para = str.split(‘.’), // get array of paragraphs
    i = 0, len = para.length, p;

    ///// -> Here, you iterate a first time through the string (+cpu), and create new arrays of strings (+memory)

    for (; i Second iteration (+cpu). 2x subStr (+cpu + memory)

    para = para.join(‘. ‘).trim(); // put everything back together

    ///// -> Third iteration (+cpu) and String creation( +memory)

    console.log(para);
    //^ “The sky is blue. Apples are green.”

    You basically use a starting point that is O(3N) and generates loads of uneeded data for a simple algorithm that is O(N) with no need for memory consumption.

    This is how I would optimize it, in terms of performance at least :

    // Don’t expect this code to work, it has not been tested !

    var str = ‘the sky is blue. apples are green.’;
    var len = str.lenght;
    var toUpper = false; // Should the next letter be transformed upper case ?

    for (var i = 0; i < len; i++) { // Only one iteration O(N)

    if (str[i] == '.') {
    toUpper = true; // The next letter should be upper case
    }
    elseif (toUpper && str[i] != ' ') { // Only if it's not a space
    str[i] = str[i].toUpperCase(); // Just transforming the letter, no memory consumption.
    toUpper = false;
    }

    }

    console.log(str);
    //^ "The sky is blue. Apples are green."

    Ok, there is plenty of things that could be abstracted here, and optimized, and it's late, so the code is probably not even working.

    But at least, it reduces memory consumption and cpu optimization, and it's readable by everyone, because it's simple.

    So how does using regular expressions here is helping, or improving Javascript ?
    We have no clues about performances of this kind of code, and most people won't be able to read it…
    Plus, writting regular expressions is very error prone.
    I just don't see how it's an improvement.

      • Cedric Ruiz,
      • February 25, 2013
      / Reply

      –“You should define what you understand as an “improved” JavaScript…”

      Well, in the case of the paragraph example I’d say the regex approach definitely looks cleaner, performs better, and if you know regex well enough then it makes for more readable code IMO. Regex is a tool for text manipulation and this seems like the perfect use case.

      Also this won’t work `str[i] = str[i].toUpperCase()`. You have to split the string into an array, change the value then join. http://jsbin.com/onacux/1/edit

      — “So how does using regular expressions here is helping, or improving Javascript ?…”

      Performance test: http://jsperf.com/loop-vs-regex-uppercase-para

      — “We have no clues about performances of this kind of code, and most people won’t be able to read it…”

      Regex is an invaluable tool for programmers. People that don’t know regex will simply keep ignoring them and manipulating simple text with loops and arrays, which is simply tedious IMO. Regex will outperform loops when manipulating text most of time.

    • Wayner,
    • March 11, 2013
    / Reply

    /^a|b|c$/.test(val)
    is still wrong
    String start only applies to the first element to test against, string end applies to the last

    Use:

    if (/^(?:a|b|c)$/.test(val)) {
    alert(‘match’);

    }

      • Cedric Ruiz,
      • March 14, 2013
      / Reply

      You’re right there. Missed that.

    • Diéssica,
    • September 14, 2013
    / Reply

    OMFG, THAT’S SO “USEFULL”! Thx!
    The best article I found about it. Hugs!

    • vsync,
    • October 27, 2013
    / Reply

    yes you’ve shrank the code but in most of your cases you’ve created havoc performance-wise :/

Leave a Reply

Your email address will not be published. Required fields are marked *

Deals

Iconfinder Coupon Code and Review

Iconfinder offers over 1.5 million beautiful icons for creative professionals to use in websites, apps, and printed publications. Whatever your project, you’re sure to find an icon or icon…

WP Engine Coupon

Considered by many to be the best managed hosting for WordPress out there, WP Engine offers superior technology and customer support in order to keep your WordPress sites secure…

InMotion Hosting Coupon Code

InMotion Hosting has been a top rated CNET hosting company for over 14 years so you know you’ll be getting good service and won’t be risking your hosting company…

SiteGround Coupon: 60% OFF

SiteGround offers a number of hosting solutions and services for including shared hosting, cloud hosting, dedicated servers, reseller hosting, enterprise hosting, and WordPress and Joomla specific hosting.

d
c