JavaScript
Article

Preparing for ECMAScript 6: New Function Syntax

By Aurelio De Rosa

In the book Secrets of the JavaScript Ninja by John Resig and Bear Bibeault, the authors describe functions as the most important concept of the language because in JavaScript everything pivots around them. Functions are very important indeed. The new version of JavaScript adds even more features to them that you’ll love to use. In this tutorial you’ll learn more about new features that work with functions and that will enable you to write even more powerful code.

If you want to know more about ECMAScript 6, I suggest you check out my articles about the String and Array data types, and newly introduced Map and WeakMap data types.

Arrow Functions

The first feature I want to cover is the arrow function. As the name suggests, to use it we’ll use an arrow (=>) that you might recognize if you’ve ever worked with PHP. This feature comes in two forms that integrate with the current function syntax. Keep in mind that by using an arrow function you can replace anonymous functions only. The two possible syntaxes are shown below:

// First syntax
([param] [, param]) => { statements }

// Second syntax
param => expression

The param placeholder represents the parameters of the function, while statements represents the body of the function. expression represents any valid expression and it’s a replacement for the right part of the first syntax ({ statements }). In the first form you can place any number of parameters between the parentheses, while the second is limited to one.

To understand what they look like, let’s say that we have a set of numbers that we need to test for even or oddness. In addition, we need to perform this test only once, so we don’t need to define an isEven() function and can use an anonymous function. Our function will return true if a number is even, and false otherwise. This results in the code below:

var numbers = [10, 21, 15, 8];

// prints "[true, false, false, true]"
console.log(
   numbers.map(function(number) {
      return number % 2 === 0;
   })
);

This is a perfect example of why arrow functions are useful. As you can see, the anonymous function is pretty simple and its body is made of a single statement. Nonetheless, to adhere to the current JavaScript syntax, we have to type a lot of additional characters. Thanks to arrow functions we can avoid them and write code like this:

var numbers = [10, 21, 15, 8];

// prints "[true, false, false, true]"
console.log(
   numbers.map(number => number % 2 === 0)
);

Much shorter isn’t it? In this case we can use the second, shorter syntax because the body of the function is made of only one statement. In addition, the only statement we had is a return. In fact, with the second syntax the result of the right expression is used as a return value.

If we want to use the arrow functions to replace functions with more statements, we can use the first form. To see it in action, let’s enhance our function to verify that the given parameter is actually a number and that it’s an integer. The resulting code is the following:

var numbers = [10, 15, false, 'test', {}];

// prints "[true, false, false, false, false]"
console.log(
   numbers.map(function(number) {
      // The parameter is a number and it's an integer
      if (typeof number !== 'number' || number % 1 !== 0) {
         return false;
      }
      return number % 2 === 0;
   })
);

We can make it shorter using the first form of arrow functions as shown below:

var numbers = [10, 15, false, 'test', {}];

// prints "[true, false, false, false, false]"
console.log(
   numbers.map(number => {
      // The parameter is a number and it's an integer
      if (typeof number !== 'number' || number % 1 !== 0) {
         return false;
      }
      return number % 2 === 0;
   })
);

A live demo of the previous code is shown below and also available as a JSFiddle.

Arrow functions aren’t only great because they allow us to save a few keystrokes. Another important feature is that they implicitly bind the this value of a function. Imagine that a given page has some buttons and that the page has the following code:

var Utility = {
    fullname: 'Aurelio De Rosa',
    handler: function (elements) {
        for (var i = 0; i < elements.length; i++) {
            elements[i].addEventListener('click', function() {
                console.log(this.fullname);
            });
        }
    }
};

var buttons = document.getElementsByTagName('button');
Utility.handler(buttons);

Any time a button is pressed the string “Aurelio De Rosa” is printed on the console. However, when the handler is attached in the for loop, the value of this won’t be the Utility object anymore but it’ll be window. Therefore, the console will display undefined.

This is a common problem in JavaScript that we can solve in a lot of different ways. For example you could store the reference to the Utility object using a variable (the classic var that = this approach) or use the bind() function. However, thanks to the introduction of the arrow function, we can fix the issue like this:

var Utility = {
  fullname: 'Aurelio De Rosa',
  handler: function (elements) {
    for (var i = 0; i < elements.length; i++) {
      elements[i].addEventListener('click', () => {
        console.log(this.fullname);
      });
    }
  }
};

var buttons = document.getElementsByTagName('button');
Utility.handler(buttons);

A live demo of the previous code is shown below and is also available as a JSFiddle.

This feature is currently only supported by Firefox 22+.

Default Values for Parameters

The new version of JavaScript has introduced another feature that PHP developers use extensively: the ability to set a default value for parameters. The JavaScript version is even more powerful than the PHP one because a default value used for a given parameter is available to the next parameters in the list. Also, in JavaScript, parameters with default values can be followed by parameters without. In PHP this is not possible. To assign a default value you have to place an equals sign right after the parameter name, followed by the default value you want to assign, as you’d do in a classic assignment.

Default values are something that we have used several times in the past but in a different way. Ponder the following code:

function Person(name, surname, gender) {
   // Set default values
   name = name || 'Aurelio';
   surname = surname || 'De Rosa';
   gender = gender || 'male';
   
   this.toString = function() {
      return 'My name is ' + name + ' ' + surname + ' and I am a ' + gender;
   }
};

// prints "My name is John Doe and I am a male"
console.log(new Person('John', 'Doe').toString());

// prints "My name is Aurelio De Rosa and I am a male"
console.log(new Person().toString());

Running this snippet of code works as expected, but the manual management of default values is really boring. Furthermore, the approach used may have unexpected results because it tests for a falsy value and then assigns a default. Let’s say that one of the parameters was a number and an ideal default value is 10 but zero is acceptable. Using the technique of the code above we could write:

param = param || 10;

In this case, because zero is a falsy value, 10 will be assigned to param which is really not what we want. Of course it’s possible to use other techniques but they require us to write even more code. Thanks to the new features of ECMAScript 6 we can avoid issues like this and shorten the code as shown below:

function Person(name = 'Aurelio', surname = 'De Rosa', gender = 'male') {  
   this.toString = function() {
      return 'My name is ' + name + ' ' + surname + ' and I am a ' + gender;
   }
};

// prints "My name is John Doe and I am a male"
console.log(new Person('John', 'Doe').toString());

// prints "My name is Aurelio De Rosa and I am a male"
console.log(new Person().toString());

This version is not only more concise but also more readable because the default values are set close to the parameters. It worth noting that the default value is used also if the argument passed in is undefined.

A live demo of the previous code is shown below and also available as a JSFiddle.

In the previous example we’ve only seen the basic use of this new feature. The next example shows how we can have parameters without a default value after one that has a default one:

function prod(number1 = 1, number2) {
   return number1 * number2;
}

The final example shows a parameter whose default value depends on a previous parameter with a default value:

function Person(name, surname, username = name + ' ' + surname) {
}

Like the previous feature this default value for a parameter is currently only supported by Firefox 15+.

Rest Parameter

The rest parameter is a special parameter that enables us to express an arbitrary number of parameters in a function. It’ll include all the passed arguments that don’t match a named parameter as elements of an array (so not an array-like element). To define this parameter, you have to place it as the last in the function’s signature and prepend three dots to it. The syntax for this parameter is reported below:

function (...paramName) {
}

paramName can be any arbitrary name you want to assign to this special parameter.

Developers has simulated this feature from a long time using arguments and removing the named parameters. To visualize the difference between the old approach and the new one, let’s say that we have a function that accepts some data about a person and prints it on the console. This function has two mandatory parameters that represent the name and the surname of the person, and then any number of additional parameters. In the old approach, such a function can be written as follows:

function presentation(name, surname) {
   var otherInfo = [].slice.call(arguments, 2);
   console.log('My name is ' + name + ' ' + surname);
   if (otherInfo.length > 0) {
      console.log('Other info: ' + otherInfo.join(', '));
   }
}

// prints "My name is John Doe"
presentation('John', 'Doe');

// Prints "My name is Aurelio De Rosa"
// "Other info: male, Italian, Web developer"
presentation('Aurelio', 'De Rosa', 'male', 'Italian', 'Web developer');

Using the rest parameter we can get rid of the first statement of the function resulting in the code listed below:

function presentation(name, surname, ...otherInfo) {
   console.log('My name is ' + name + ' ' + surname);
   if (otherInfo.length > 0) {
      console.log('Other info: ' + otherInfo.join(', '));
   }
}

// prints "My name is John Doe"
presentation('John', 'Doe');

// Prints "My name is Aurelio De Rosa"
// "Other info: male, Italian, Web developer"
presentation('Aurelio', 'De Rosa', 'male', 'Italian', 'Web developer');

A live demo of the previous code is shown below and also available as a JSFiddle.

This feature is currently only supported by Firefox 15+.

Conclusion

In this tutorial we’ve covered the new features introduced in ECMAScript 6 that work with functions. They will allow us to write even more powerful and concise code. Due to the poor support of browsers they aren’t something that can you really use today, but you should be prepared because this is what the future of JavaScript looks like.

  • Tatsh

    I like the arrow function but I’m disappointed at the symbol not being -> like in CoffeeScript. Also return should be an optional keyword in arrow functions (arguably in any function). I guess I am pretty used to CoffeeScript.

    I also think it is a bit cludgy to type …argList for the rest of the arguments passed in. In Python this is simply *args. In PHP 5.6 we got …$args which is even more cludgy due to the $ but that is not unexpected.

    • VoidPhantom

      Actually, the fat arrow => is just like in CoffeeScript, seeing as it, too, captures the this value.

      • Tatsh

        Thanks. Did not know that and just tried it out.


        class A
        c: [1]
        new A().c.forEach =>
        console.log this

        {}

        where as -> gives global this (window in browser).

  • Cesidio DiBenedetto

    Small correction:

    In your first example, `testNumber` should be `number` otherwise it throws a `ReferenceError: testNumber is not defined`

    • paulwilkins

      Thanks Cesidio for catching that.

  • Sebastian

    The example “function prod(…” (for parameters without a default value after one that has a default one) doesn’t work. I tested in FF Developer Edition (35.0a2).

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in JavaScript, once a week, for free.