Master JavaScript arrow functions and (x) => x syntax. Learn about lexical this binding, when to use arrow functions, and differences from regular functions.

Master JavaScript arrow functions and (x) => x syntax. Learn about lexical this binding, when to use arrow functions, and differences from regular functions.

Arrow functions use => syntax:

// Traditional function
function square(x) {
    return x * x;
}

// Arrow function
const square = (x) => x * x;

Both do the same thing, but the arrow version is shorter.

Basic Syntax

Single parameter, single expression:

const double = x => x * 2;

No parentheses needed around single parameter. Implicit return.

Multiple parameters:

const add = (a, b) => a + b;

Parentheses required for multiple parameters.

No parameters:

const getRandom = () => Math.random();

Empty parentheses required.

Multiple statements:

const greet = (name) => {
    const message = `Hello, ${name}!`;
    return message;
};

Curly braces and explicit return needed for multiple statements.

Implicit Return

Single-expression arrows return automatically:

const square = x => x * x;  // Returns x * x

Equivalent to:

const square = x => {
    return x * x;
};

But returning object literals requires parentheses:

const makePerson = name => ({ name: name });  // Parentheses needed

Without parentheses, JavaScript interprets {} as a block, not an object.

The 'this' Difference

This is the crucial difference. Arrow functions don't have their own this. They inherit this from the enclosing scope:

function Person() {
    this.age = 0;
    
    setInterval(function() {
        this.age++;  // 'this' is window/global, not Person
    }, 1000);
}

// Fixed with arrow function
function Person() {
    this.age = 0;
    
    setInterval(() => {
        this.age++;  // 'this' is Person instance
    }, 1000);
}

Traditional functions create their own this. Arrow functions use the this from where they're defined.

Lexical this Binding

"Lexical" means the value is determined by where the function is written, not where it's called:

const obj = {
    name: 'Alice',
    traditional: function() {
        console.log(this.name);  // 'Alice'
    },
    arrow: () => {
        console.log(this.name);  // undefined (this is global/window)
    }
};

obj.traditional();  // Works
obj.arrow();        // Doesn't work as expected

The arrow function's this was set when the object was created (global scope), not when the method was called.

When to Use Arrow Functions

Callbacks and array methods:

[1, 2, 3].map(x => x * 2);
[1, 2, 3].filter(x => x > 1);
[1, 2, 3].reduce((sum, x) => sum + x, 0);

Event handlers where you need outer this:

class Button {
    constructor() {
        this.count = 0;
        document.querySelector('button').addEventListener('click', () => {
            this.count++;  // 'this' is Button instance
        });
    }
}

Promises and async code:

fetch('/api/data')
    .then(response => response.json())
    .then(data => console.log(data));

When NOT to Use Arrow Functions

Object methods:

const person = {
    name: 'Bob',
    greet: () => {
        console.log(`Hi, I'm ${this.name}`);  // 'this' is not person
    }
};

// Use traditional function instead
const person = {
    name: 'Bob',
    greet() {
        console.log(`Hi, I'm ${this.name}`);  // Works correctly
    }
};

Prototype methods:

Person.prototype.greet = () => {
    console.log(this.name);  // Wrong 'this'
};

// Use traditional function
Person.prototype.greet = function() {
    console.log(this.name);  // Correct 'this'
};

Constructors:

const Person = (name) => {
    this.name = name;  // Error: arrow functions can't be constructors
};

new Person('Alice');  // TypeError

No arguments Object

Arrow functions don't have an arguments object:

function traditional() {
    console.log(arguments);  // Works
}

const arrow = () => {
    console.log(arguments);  // ReferenceError
};

// Use rest parameters instead
const arrow = (...args) => {
    console.log(args);  // Works
};

Can't Be Used with new

Arrow functions aren't constructors:

const Person = (name) => {
    this.name = name;
};

new Person('Alice');  // TypeError: Person is not a constructor

No prototype Property

Arrow functions don't have .prototype:

const arrow = () => {};
console.log(arrow.prototype);  // undefined

function regular() {}
console.log(regular.prototype);  // Object

Performance

Arrow functions are slightly faster to create (no this binding, no arguments object, no prototype). The difference is negligible in most code.

Style Considerations

Some teams prefer consistency—always arrow or always traditional. Others use arrow for callbacks and traditional for methods.

Airbnb style guide recommends:

  • Arrow functions for callbacks
  • Traditional functions for top-level functions and methods

Async Arrow Functions

Arrow functions work with async/await:

const fetchData = async () => {
    const response = await fetch('/api/data');
    return response.json();
};

Higher-Order Functions

Arrow functions excel at functional programming:

// Function composition
const compose = (f, g) => x => f(g(x));

const add1 = x => x + 1;
const double = x => x * 2;

const add1ThenDouble = compose(double, add1);
add1ThenDouble(3);  // 8

Currying

Arrow syntax makes currying readable:

const add = a => b => a + b;

const add5 = add(5);
add5(3);  // 8

Equivalent to:

function add(a) {
    return function(b) {
        return a + b;
    };
}

Common Mistakes

Forgetting parentheses for object returns:

const makePerson = name => { name: name };  // Wrong - empty block
const makePerson = name => ({ name: name });  // Correct

Using arrow for methods needing dynamic this:

const button = {
    text: 'Click me',
    click: () => {
        console.log(this.text);  // undefined
    }
};

Expecting arguments object:

const fn = () => {
    console.log(arguments);  // ReferenceError
};

Browser Support

Arrow functions work in all modern browsers. IE11 doesn't support them. Transpile with Babel if IE11 support is needed.

Further Reading

MDN's arrow function documentation covers all behaviors and edge cases.

The ECMAScript specification defines arrow function semantics precisely.

Kyle Simpson's You Don't Know JS: ES6 & Beyond has a chapter on arrow functions and their this binding.

Arrow functions are now the standard for callbacks and functional code in JavaScript.

Wear the code

Product mockup

(x) => x; Developer T-Shirt (JavaScript Edition — Dark Mode)

£25.00

View product
Product mockup

(x) => x; Developer T-Shirt (JavaScript Edition — Light Mode)

£25.00

View product
Product mockup

=> Developer T-Shirt (Code Edition — Dark Mode)

£25.00

View product
Product mockup

=> Developer T-Shirt (Code Edition — Light Mode)

£25.00

View product

0 comments

Leave a comment

Please note, comments need to be approved before they are published.