Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are 'Arrow Functions' and 'Functions' equivalent / interchangeable?

Arrow functions in ES2015 provide a more concise syntax.

  • Can I replace all my function declarations / expressions with arrow functions now?
  • What do I have to look out for?

Examples:

Constructor function

function User(name) {   this.name = name; }  // vs  const User = name => {   this.name = name; }; 

Prototype methods

User.prototype.getName = function() {   return this.name; };  // vs  User.prototype.getName = () => this.name; 

Object (literal) methods

const obj = {   getName: function() {     // ...   } };  // vs  const obj = {   getName: () => {     // ...   } }; 

Callbacks

setTimeout(function() {   // ... }, 500);  // vs  setTimeout(() => {   // ... }, 500); 

Variadic functions

function sum() {   let args = [].slice.call(arguments);   // ... }  // vs const sum = (...args) => {   // ... }; 
like image 791
Felix Kling Avatar asked Dec 18 '15 17:12

Felix Kling


People also ask

What is the difference between a function and an arrow function?

Unlike regular functions, arrow functions do not have their own this . The value of this inside an arrow function remains the same throughout the lifecycle of the function and is always bound to the value of this in the closest non-arrow parent function.

Should I use arrow functions or functions?

The takeaway: Function expressions are best for object methods. Arrow functions are best for callbacks or methods like map, reduce, or forEach.

Are Lambda and arrow functions the same?

JavaScript arrow functions are roughly the equivalent of lambda functions in python or blocks in Ruby. These are anonymous functions with their own special syntax that accept a fixed number of arguments, and operate in the context of their enclosing scope - ie the function or other code where they are defined.

When should you not use arrow functions?

An arrow function doesn't have its own this value and the arguments object. Therefore, you should not use it as an event handler, a method of an object literal, a prototype method, or when you have a function that uses the arguments object.


2 Answers

tl;dr: No! Arrow functions and function declarations / expressions are not equivalent and cannot be replaced blindly.
If the function you want to replace does not use this, arguments and is not called with new, then yes.


As so often: it depends. Arrow functions have different behavior than function declarations / expressions, so let's have a look at the differences first:

1. Lexical this and arguments

Arrow functions don't have their own this or arguments binding. Instead, those identifiers are resolved in the lexical scope like any other variable. That means that inside an arrow function, this and arguments refer to the values of this and arguments in the environment the arrow function is defined in (i.e. "outside" the arrow function):

// Example using a function expression function createObject() {   console.log('Inside `createObject`:', this.foo);   return {     foo: 42,     bar: function() {       console.log('Inside `bar`:', this.foo);     },   }; }  createObject.call({foo: 21}).bar(); // override `this` inside createObject

// Example using a arrow function function createObject() {   console.log('Inside `createObject`:', this.foo);   return {     foo: 42,     bar: () => console.log('Inside `bar`:', this.foo),   }; }  createObject.call({foo: 21}).bar(); // override `this` inside createObject

In the function expression case, this refers to the object that was created inside the createObject. In the arrow function case, this refers to this of createObject itself.

This makes arrow functions useful if you need to access the this of the current environment:

// currently common pattern var that = this; getData(function(data) {   that.data = data; });  // better alternative with arrow functions getData(data => {   this.data = data; }); 

Note that this also means that is not possible to set an arrow function's this with .bind or .call.

If you are not very familiar with this, consider reading

  • MDN - this
  • YDKJS - this & Object prototypes

2. Arrow functions cannot be called with new

ES2015 distinguishes between functions that are callable and functions that are constructable. If a function is constructable, it can be called with new, i.e. new User(). If a function is callable, it can be called without new (i.e. normal function call).

Functions created through function declarations / expressions are both constructable and callable.
Arrow functions (and methods) are only callable. class constructors are only constructable.

If you are trying to call a non-callable function or to construct a non-constructable function, you will get a runtime error.


Knowing this, we can state the following.

Replaceable:

  • Functions that don't use this or arguments.
  • Functions that are used with .bind(this)

Not replaceable:

  • Constructor functions
  • Function / methods added to a prototype (because they usually use this)
  • Variadic functions (if they use arguments (see below))
  • Generator functions, which require the function* notation

Lets have a closer look at this using your examples:

Constructor function

This won't work because arrow functions cannot be called with new. Keep using a function declaration / expression or use class.

Prototype methods

Most likely not, because prototype methods usually use this to access the instance. If they don't use this, then you can replace it. However, if you primarily care for concise syntax, use class with its concise method syntax:

class User {   constructor(name) {     this.name = name;   }      getName() {     return this.name;   } } 

Object methods

Similarly for methods in an object literal. If the method wants to reference the object itself via this, keep using function expressions, or use the new method syntax:

const obj = {   getName() {     // ...   }, }; 

Callbacks

It depends. You should definitely replace it if you are aliasing the outer this or are using .bind(this):

// old setTimeout(function() {   // ... }.bind(this), 500);  // new setTimeout(() => {   // ... }, 500); 

But: If the code which calls the callback explicitly sets this to a specific value, as is often the case with event handlers, especially with jQuery, and the callback uses this (or arguments), you cannot use an arrow function!

Variadic functions

Since arrow functions don't have their own arguments, you cannot simply replace them with an arrow function. However, ES2015 introduces an alternative to using arguments: the rest parameter.

// old function sum() {   let args = [].slice.call(arguments);   // ... }  // new const sum = (...args) => {   // ... }; 

Related question:

  • When should I use arrow functions in ECMAScript 6?
  • Do ES6 arrow functions have their own arguments or not?
  • What are the differences (if any) between ES6 arrow functions and functions bound with Function.prototype.bind?
  • How to use arrow functions (public class fields) as class methods?

Further resources:

  • MDN - Arrow functions
  • YDKJS - Arrow functions
like image 176
Felix Kling Avatar answered Sep 28 '22 01:09

Felix Kling


Arrow functions => best ES6 feature so far. They are a tremendously powerful addition to ES6, that I use constantly.

Wait, you can't use arrow function everywhere in your code, its not going to work in all cases like this where arrow functions are not usable. Without a doubt, the arrow function is a great addition it brings code simplicity.

But you can’t use an arrow function when a dynamic context is required: defining methods, create objects with constructors, get the target from this when handling events.

Arrow functions should NOT be used because:

  1. They do not have this

    It uses “lexical scoping” to figure out what the value of “this” should be. In simple word lexical scoping it uses “this” from the inside the function’s body.

  2. They do not have arguments

    Arrow functions don’t have an arguments object. But the same functionality can be achieved using rest parameters.

    let sum = (...args) => args.reduce((x, y) => x + y, 0) sum(3, 3, 1) // output - 7 `

  3. They cannot be used with new

    Arrow functions can't be constructors because they do not have a prototype property.

When to use arrow function and when not:

  1. Don't use to add function as a property in object literal because we can not access this.
  2. Function expressions are best for object methods. Arrow functions are best for callbacks or methods like map, reduce, or forEach.
  3. Use function declarations for functions you’d call by name (because they’re hoisted).
  4. Use arrow functions for callbacks (because they tend to be terser).
like image 31
Ashutosh Avatar answered Sep 27 '22 23:09

Ashutosh