Arrow functions
Learn JavaScript arrow function syntax, implicit returns, lexical this, arguments, and when a regular function is the better tool.
- 01Read arrow syntaxConvert small function expressions into arrows without changing the result.
- 02Use implicit returns safelyKnow when braces need
return, and why object literals need parentheses. - 03Choose the right function kindExplain why arrows do not have their own
this,arguments,prototype, or constructor behavior.
A shorter function shape
An arrow function is a compact way to write a function value: (input) => result. It is still a function. You can store it in a variable, pass it to another function, and call it with parentheses.
Arrows are popular because JavaScript programs often pass small functions as callbacks. In the Declaring & calling functions lesson, you learned the full recipe-card version. Arrows are the sticky-note version: short, quick, and best for small jobs.
Imagine a recipe card for a cake: ingredients, timing, and careful steps. Now imagine a sticky note on your desk that says “double each score.” Arrow functions are that sticky note. They shine when the task is small enough that the short form helps instead of hiding the idea.
- In real life: A full recipe card with title and steps
- In JavaScript: A named function declaration
- In real life: A sticky note: “toast bread, add jam”
- In JavaScript: A tiny arrow callback
- In real life: Easy to read when the job is small
- In JavaScript: Great for
map,filter, and one-line helpers
Where the analogy stops: A sticky note is not better for every recipe. When a function needs a clear name, its own this, its own arguments, or constructor behavior, use a regular function.
Arrow functions are function expressions with shorter syntax and lexical this. “Lexical” means they borrow this from where they were written instead of getting a fresh one when called.
This lesson covers four things in order: arrow syntax, implicit returns, what arrows do not have, and when not to use them. We will mention The this keyword, Methods & this, Arrow functions & lexical this, and Constructors & new by title only because those deeper lessons come later.
Arrow syntax
STEP THROUGHStart with a function expression. It creates a function value and stores it in a variable. An arrow does the same job with fewer words:
const doubleA = function (number) { return number * 2;}; const doubleB = (number) => { return number * 2;}; const doubleC = (number) => number * 2;const doubleD = number => number * 2; console.log(doubleA(6), doubleB(6), doubleC(6), doubleD(6));The parameter list goes on the left of =>. The work goes on the right. If there are zero parameters, use (). If there are two or more parameters, use parentheses. If there is exactly one simple parameter, the parentheses are optional.
Use the setting to shrink the same helper. Predict the output before you step; the syntax changes, but the value stays the same.
script
return number * 2;}; console.log(double(6));Keep the Code style lesson’s advice in mind: shorter is not automatically clearer. Use the shape that lets a beginner read the code aloud.
Implicit return
INTERACTIVEA concise arrow can return one expression without writing return. Think of it like a vending machine: you press the button, and the result comes straight out.
With price => price * 0.2, there is no block to walk through. The expression on the right is the value the function hands back.
- In real life: Press one button
- In JavaScript: Call a one-expression arrow
- In real life: The can drops out immediately
- In JavaScript: The expression value is returned
- In real life: Open the service door and do repairs
- In JavaScript: Use braces for several statements
Where the analogy stops: Real vending machines can do many hidden steps. A concise arrow has exactly one expression. If you add braces, you must write return yourself.
The biggest beginner trap is returning an object. In JavaScript, a bare { after => starts a block, just like you learned in Statements. To return an object literal implicitly, wrap the object in parentheses.
Parentheses decide whether braces mean “object value” or “function body.” Step through both calls.
script
const brokenLabel = name => { name: name }; console.log(makeLabel("Ada").name);console.log(brokenLabel("Ada"));If the body has several statements, use braces and return: { const total = price + tax; return total; }. Do not hide a multi-step job inside a clever one-liner.
No own this
INTERACTIVEA regular function gets its this from how it is called. An arrow does not. It borrows this from the place where it was written.
If a method says this.name, it needs the object's address. A regular method gets an address from its call. An arrow uses the address from outside where it was written.
- In real life: A new note gets its own address
- In JavaScript: A regular method gets its own
thisfrom the call - In real life: A note uses the room's address
- In JavaScript: An arrow borrows the outer
this - In real life: The wrong room gives the wrong address
- In JavaScript: An arrow method may not point at the object
Where the analogy stops: this has several binding rules. For now, remember that arrows do not create their own this.
"use strict";function makeUser() { return { name: "Ada", regular() { return this.name; }, arrow: () => this.name, };} const user = makeUser();console.log(user.regular());console.log(user.arrow());Result
The regular method is called as user.regular(), so this is the user object and the result is Ada.
this as arrows.The arrow method above is deliberately written inside a strict factory so the outer this is undefined. ES module top-level code also has undefined as top-level this. In classic browser scripts, top-level this may be the global object instead. Either way, it is not the object you wanted.
But arrows are excellent inside regular methods when a callback should keep the method’s this.
This is the classic good use for arrows: a short callback that should keep the surrounding method's this.
script
name: "Debuggers", members: ["Ada", "Lin"], labels() { return this.members.map(member => this.name + ": " + member); },}; console.log(team.labels().join(" | "));No own arguments, prototype, or new
COMPAREArrows are intentionally smaller than regular functions. They do not create their own arguments object. If you mention arguments inside an arrow, JavaScript looks outside the arrow. At the top level of a module, there is no outer arguments, so that would be a ReferenceError.
function outer(first, second) { const arrow = () => arguments[0] + " / " + arguments.length; return arrow("inner");} console.log(outer("outer", "second"));Prefer rest parameters when you want a list of arguments: const collect = (...items) => items.length;. Rest parameters are explicit and work in both regular and arrow functions.
const User = name => ({ name });console.log(User("Ada").name);console.log(new User("Ada"));An arrow has no prototype property for instances and cannot be called with new. In V8 environments such as Chrome and Node, new User("Ada") throws a TypeError: User is not a constructor. The exact wording can vary by engine, so learn the rule, not the message.
function outer(first, second) { const arrow = () => arguments[0] + " / " + arguments.length; return arrow("inner");} console.log(outer("outer", "second"));The arrow reads arguments from outer; its own call with "inner" does not create a new arguments object.
When not to use arrows
Arrow functions are a tool, not a style requirement. Prefer a regular function or method when the function needs its own calling context, a useful name, or constructor behavior.
| Question | Regular function | Arrow function |
|---|---|---|
| Basic shape | function add(a, b) { return a + b; } | (a, b) => a + b |
this | Gets a this from how it is called | Borrows this from where it was written |
arguments | Has its own arguments object | No own arguments; use rest parameters |
new | Can be a constructor if written for that job | Cannot be used with new; no prototype property |
| Hoisting | Function declarations are available before their line | Usually stored in const; the variable is not usable before that line |
| Best use | Methods, constructors, named reusable operations | Short callbacks and tiny helpers |
An array callback: `scores.map(score => score * 2)`An object method that reads `this.name`- A function you plan to call with
newIt belongs in Prefer regular. Arrows cannot be constructors and do not have a
prototypeproperty. A one-line helper: `const tax = price => price * 0.1`- A callback inside a method that should keep the method's
this Code that needs its own `arguments` object
Sort each scenario. If a wrong answer surprises you, read its explanation before moving on.
In the Events lessons, some event handlers rely on this being the element that received the event. Those handlers should be regular functions. Other event handlers use event.currentTarget instead and can be arrows.
Where you'll use arrow functions
Most beginner code uses arrows in array callbacks and tiny helpers. They keep the important operation close to the data.
const prices = [5, 12, 20];const withTax = prices.map(price => price * 1.1);const affordable = withTax.filter(price => price < 15); const cart = { label: "Cart", items: ["book", "pen"], lines() { return this.items.map(item => this.label + ": " + item); },}; console.log(affordable.join(", "));console.log(cart.lines().join(" | "));Notice the pattern: arrows are callbacks passed to map and filter. The object still uses a regular method for lines(), because that method needs this to be cart.
Common misconceptions
“Arrows are just shorter functions.”
They are shorter, but not identical. The big differences are this, arguments, prototype, and new.
“An arrow with braces returns the last line.”
No. Braces create a block. You need return, or the function returns undefined.
“Arrows are always better style.”
No. Short callbacks are great. Object methods that use this, constructors, and complex named operations are usually clearer as regular functions.
“The object before the dot becomes this for an arrow.”
That dot-call rule applies to regular functions. Arrows ignore it and use outer this.
“Use arguments in arrows for extra values.”
Use rest parameters instead: (...values) => values.length.
const makeLabel = name => ({ name, active: true });const brokenLabel = name => { name: name }; console.log(makeLabel("Ada").name);console.log(brokenLabel("Ada"));Practice: choose and fix arrows
5 EXERCISESRewrite the function expression as an arrow without changing the output.
const add = function (a, b) {
return a + b;
};
console.log(add(2, 3));const add = (a, b) => a + b;
console.log(add(2, 3));The arrow has the same two parameters and the same returned expression, so it prints 5.
This arrow is meant to return an object. Fix it, then type the printed value.
const makePoint = (x, y) => { x, y };
console.log(makePoint(2, 4).y);const makePoint = (x, y) => ({ x, y });
console.log(makePoint(2, 4).y);Parentheses make the braces an object value. The returned point has y: 4.
Predict what the regular method returns before the arrow method throws.
"use strict";
function makeUser() {
return {
name: "Ada",
regular() { return this.name; },
arrow: () => this.name,
};
}
const user = makeUser();
console.log(user.regular());
console.log(user.arrow());user.regular() returns Ada. The next line, user.arrow(), throws in this strict example because the arrow borrowed undefined instead of receiving user.
You are writing an object method that uses this.name. Type the safer choice: arrow or regular.
Use a regular method. Arrows are better for the small callbacks inside that method, not for the method itself when it needs this.
Run the callback example. What exact string is printed?
const team = {
name: "Debuggers",
members: ["Ada", "Lin"],
labels() {
return this.members.map(member => this.name + ": " + member);
},
};
console.log(team.labels().join(" | "));const team = {
name: "Debuggers",
members: ["Ada", "Lin"],
labels() {
return this.members.map(member => this.name + ": " + member);
},
};
console.log(team.labels().join(" | "));The regular method receives team as this. The arrow callback borrows that same this, so both labels include Debuggers.
Quiz: check your understanding
7 QUESTIONSQuestion 1 of 7Which arrow is equivalent to
function (x) { return x * 2; }?Choose an answer to see the explanation.
Question 2 of 7What does the object-returning arrow print?
Read the code, then predictconst make = () => ({ a: 1 }); console.log(make().a);Choose an answer to see the explanation.
Question 3 of 7What does the block-bodied arrow print?
Read the code, then predictconst make = () => { a: 1 }; console.log(make());Choose an answer to see the explanation.
Question 4 of 7Why should an object method that uses
this.nameusually not be an arrow?Choose an answer to see the explanation.
Question 5 of 7What does the borrowed arguments example print?
Read the code, then predictfunction outer(first, second) { const arrow = () => arguments[0] + " / " + arguments.length; return arrow("inner"); } console.log(outer("outer", "second"));Choose an answer to see the explanation.
Question 6 of 7Which statement about
new (() => {})is true?Choose an answer to see the explanation.
Question 7 of 7Best choice for
numbers.map(_____ )when the callback isnumber * 10?Choose an answer to see the explanation.
Key takeaways
- Arrow functions are compact function expressions:
(value) => result. - A concise arrow returns its expression automatically; braces require
return. - Wrap object literals in parentheses:
() => ({ a: 1 }). - Arrows have no own
this,arguments,prototype, or constructor behavior. - Use arrows for short callbacks; avoid them for methods that need
this, constructors, and code that needsarguments.
Remember the one-liner.
An arrow function is a short function expression that returns small results neatly and borrows this from where it was written.
Up next: Recursion.