In JavaScript there are a number of ways to declare functions. In ES6 arrow functions were added, and this article will explain their usage, and some possible pitfalls when using them.
Other Ways To Define Javascript Functions
The most familiar ways, especially if you’re looking at older code are the typical function statement:
sayHello = function() { console.log("Hello") } sayHello() // Hello
And the function expression:
sayHello = function() { console.log("Hello") } sayHello() // Hello
Defining Arrow Functions
This could be rewritten as an arrow function in the following manner:
sayHello = () => { console.log("Hello") } sayHello() // Hello
Now you’re probably saying to yourself, that’s nice, but all we’re doing is not writing the word function, big deal. Are they faster or something? (and no they’re not).
They are a nice addition though and let me show you why. You can take a function and rewrite it in a single as:
sayHello => console.log("Hello") sayHello() // Hello
You may have heard of lambdas, or lamba functions in other programming languages, and yes this is the Javascript rendition.
They were officially made part of JavaScript with ES6, but existed earlier most famously with CoffeeScript (an older language that transpired to JavaScript that inspired many JavaScript language features that were to come).
The arrow function syntax becomes even more useful when you rewrite functions that return values in a single line:
returnHello => () => "Hello" console.log(returnHello) // Hello
No need for the return statement with single line arrow functions.
You can also drop the parameter brackets when having a single parameter:
helloName = name => console.log("Hello " + name) helloName()
This concise syntax becomes very useful when using other functions that take a function as a parameter, such as the built in map function.
myArray.map(item => item.trim())
Problems With Arrow Functions
Now at this point I hope you’re clear on how arrow functions can make code more concise, but as always there are some caveats.
Returning An Object
One caveat occurs simply because of the syntax which is, if you’re simply returning an empty object with the function, you’ll need to add extra brackets in that case like this:
returnEmptyObject = () => ({}); returnEmptyObject(); // returns {}
because written like this, it can’t be determined whether the brackets are opening and closing brackets or an object:
returnEmptyObject = () => {}; returnEmptyObject(); // returns nothing
Arrow Function Scope
There is also a difference in scope when using arrow functions, they gain the scope based on where they are placed, not based on the function caller.
This becomes evident when using the this keyword, because arrow functions gain the scope based on where they were placed and not on how they are called this leads to this being undefined.
Regular functions in an object:
const object = { object_text: "I'm an object.", get_text: function() { return this.object_text; }, }; console.log(object.get_text()); // I'm an object
const object = { object_text: "I'm an object.", get_text: () => { return this.object_text; }, }; console.log(object.get_text()); // undefined
Definitely something to be aware of, and this is why you won’t see arrow functions used as object methods.
Also note, that since arrow functions gain their scope based on where they are called they have to be defined first before they are used.
No Arguments Object
Unlike regular functions arrow functions don’t have their own arguments object. Trying to access the arguments object will give an undefined
function regularFunction() { console.log(arguments[0]) } regularFunction("argument") // argument
arrowFunction = () => { console.log(arguments[0]) } arrowFunction("argument") // Error arguments is not defined
Conclusion
Arrow functions are a great way to shorten code. However there are caveats that a good practice not use them unless you are creating a single line function or need to use their different scope properties.