💾 Archived View for njms.ca › gemlog › modern-js-arrow-functions.gmi captured on 2024-08-31 at 11:53:51. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2024-05-26)

-=-=-=-=-=-=-

Return to index

Modern JS concepts: Arrow functions, the new and improved function literals

In the past, we would see a lot of this:

someFunction(param, function() {
  // do something
});

Now, this gets a little bit cumbersome after a while. Not only are function expressions long, they include a kitchen sink of features that you probably won't need in all cases, like the `this` or a `new` constructor.

Thankfully, in EMCAScript 6, we got this whole new and improved arrow function. Let's take a look.

Syntax

The declaration of an arrow function goes like this:

(param1, param2 ... paramN) => expression

Arrow functions may remind you of the lambda or anonymous function syntax used various other programming languages like Haskell:

someFunction(param, () => {
  // do something
});

As you can see, they're defined with the parameters wrapped in brackets, followed by an `=>` arrow and an expression. If your arrow function doesn't need any parameters, you can just use two empty brackets as I did above. Here's another example:

var array = [1, 2, 3, 4];
var increment = 2;

var incremented = array.map(item => item + increment); // [3, 4, 5, 6]

When writing arrow functions like this (without using `{}` curly braces), you don't even need to use the `return` keyword, similar to how you would return a value in a language like Rust. It's implied that, since there's only one expression that needs to be evaluated, it should be returned.

In that example, we didn't use brackets around the argument `param`. When you only have one parameter, brackets are optional.

Advantages

One of the things that makes arrow functions so useful is that they don't have their own `this` object. Consider the following:

var object = {
  values: [2, 4, 6, 8],
  multiplyBy: 7,
  multiply() { // ES6 also let's us write functions in objects like this
    return this.values.map(function (value) {
      return value * this.multiplyBy;
    })
  }
}

However, if we try to run this, we'll get an `Array [ NaN, NaN, NaN, NaN ]` value. Why, you ask? Try taking a closer look at that anonymous function.

As I explained in my article on closures, Every nested function takes on the *lexical scope* of the function it's nested in. In other words, all values made available in the outer function exist in the inner function. For this reason, we might expect that the `this` object should be available as well. However, the anonymous function you're working in already has it's own `this` which takes superiority.

Closures in programming: What are they and how do they work?

Though we might have access to `multiplyBy` in the outer function, getting to it within the inner function is a bit more difficult. Before ES6, people often used this hack:

var self = this;

return this.values.map(function (value) {
  return value * self.multiplyBy;
})

Sure, this works, but it's a bit of a compromise. Thankfully, arrow functions solve this issue beautifully.

var object = {
  values: [2, 4, 6, 8],
  multiplyBy: 7,
  multiply() {
    return this.values.map(value => value * this.multiplyBy);
  }
}

Since arrow functions don't have `this`, no referencing is required to access the `multiplyBy` value.

Perfect.

Another (practical) use case

Let's take a look at this function I wrote to simplify the process of querying an API with an AJAX call using jQuery:

function queryAPI(query, datatype, callback) {
  return $.ajax({
    url: query,
    dataType: datatype,
    success: callback.success,
    error: callback.error
  });
}

The function takes three parameters: the complete URL, the data type and a success and error callback wrapped in an object. We can call this function like so:

queryAPI("https://api.example.com/some/query", "json", {
  success: function(data) {
    element.innerHTML = data;
  },
  error: function(error) {
    element.innerHTML = error;
  }
})

Now that we know more about arrow functions, things would look a lot nicer written like this:

queryAPI("https://api.example.com/some/query", "json", {
  success: data => element.innerHTML = data,
  error: error => element.innerHTML = error
})

EMCAScript 6 is full of great features. Sure, many of them might not be supported natively in all browsers yet, but that doesn't mean it's too early to start!

Further reading

Arrow functions (developer.mozilla.org)

ES6 In Depth: Arrow functions

Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?

*Agree or disagree? Think I missed or poorly explained something important? Questions, comments or concerns? Leave a comment down below!*

---

"Modern JS concepts: Arrow functions, the new and improved function literals" was published on 2017-12-28

If you have thoughts you'd like to share, send me an email!

See here for ways to reach out