Skip to main content

Menu

System onlineAI Tutorials / 2026

AI Tutorials
Knowledge search

Recent · Popular · Tutorials

  • dart3 tutorials
  • java1 tutorial
  • Javascript3 tutorials
  • Node.js Introduction2 tutorials
  • dartdart · General · In depth
  • JavascriptJavascript · Advanced · In depth
  • JavascriptJavascript · Advanced · Mid
  • JavascriptJavascript · Advanced · Short

Find a tutorial

Tell the assistant what you want to learn. It suggests published chapters.

For example: “I want to learn Rust ownership from the start.” The conversation is kept only in this tab.

0 / 2,000 characters

Enter to send, Shift+Enter for a new line. Do not include personal information.

Chapter 4

Functions: Declarations, Expressions, and Arrows

This chapter assumes you are comfortable with variables, scope, and control flow from earlier chapters, and that you know what a value is in JavaScript. We go straight into the internal differences between the three function forms and the decision criteria for choosing among them.
Level: AdvancedLength: Mid2 min read

Read at another depth

Functions: Declarations, Expressions, and Arrows

Prerequisites

This chapter assumes you are comfortable with variables, scope, and control flow from earlier chapters, and that you know what a value is in JavaScript. We go straight into the internal differences between the three function forms and the decision criteria for choosing among them.

Three Forms, One Concept

All three syntaxes create function objects, but they differ in hoisting, this binding, arguments, and constructibility:

Code example in javascript
// Declaration: hoisted fully, has its own this and arguments, constructible
function add(a, b) { return a + b; }

// Function expression: the value is bound when that line runs
const multiply = function (a, b) { return a * b; };

// Arrow: lexical this, no arguments object, not constructible
const double = (n) => n * 2;

Declarations are hoisted with their body — you can call them before the line where they appear. Function expressions hoist only the binding (const/let bindings are in the temporal dead zone until initialized), not the assignment. Arrows are always expressions.

`this` and the Arrow Exception

The decisive difference is this. Regular functions receive this from the call site; arrows close over the this of their defining scope, exactly like any other variable:

Code example in javascript
const timer = {
  ticks: 0,
  start() {
    setInterval(() => {
      this.ticks += 1; // arrow: this comes from start()
    }, 1000);
  },
};
timer.start();

A regular function passed to setInterval would have this === undefined (strict mode) or the global object. This is the classic reason arrows exist — but it cuts both ways.

Failure Modes and Gotchas

  • Arrows as methods: const obj = { name: 'x', greet: () => this.name } loses this. Use a method shorthand or a regular function.
  • Arrows as constructors: new (arrowFn) throws a TypeError. Arrows have no [[Construct]] internal slot.
  • No arguments: arrows must use rest parameters ((...args) => args.length), which is often the better API anyway.
  • Named vs. anonymous expressions: const f = function helper() {} gives stack traces a name even if f is reassigned. Prefer named expressions when debugging matters.
  • Hoisting order: mutual recursion between function expressions fails if defined in the wrong order; declarations don't have this problem.

Object Identity and Equality

All three forms create distinct function objects. Comparing or using them as Map keys requires care:

Code example in javascript
function f() {}
const g = f;
console.log(f === g); // true — same reference
const h = () => {};
console.log(f === h); // false — different objects

Decision Criteria

SituationPreferred formWhy
Top-level utilityDeclarationHoisting, clear name in traces
Callback needing `this` from enclosing scopeArrowLexical `this`
Object/class methodMethod shorthandDynamic `this`
Constructor`class` or declarationArrows cannot be constructed
One-off inline callbackArrow (concise body)Minimal ceremony

A concise arrow body ((n) => n * 2) implicitly returns an object literal only if you wrap it: () => ({ a: 1 }), not () => { a: 1 }, which is a labeled block returning undefined — a common silent bug.

Code example in javascript
const makePoint = (x, y) => ({ x, y }); // explicit parens required
console.log(makePoint(1, 2).x); // 1

Exercise

Why does replacing a method shorthand with an arrow break code that reads other properties via this, and what are two fixes?

Show answer

An arrow has no dynamic this; it captures this lexically from the enclosing scope (often undefined in module top-level strict code). Fix 1: use the method shorthand (name() {}). Fix 2: bind a regular function or restructure so the callback is an arrow nested inside a regular method, as in the timer example.

Exercise

What does () => { a: 1 } return, and why?

Show answer

undefined. The braces are parsed as a function body, a: 1 is a labeled statement, and nothing is returned. To return an object literal you need parentheses: () => ({ a: 1 }).

Spotted a mistake, or code that does not work?

Report an issue

Chapter: Functions: Declarations, Expressions, and Arrows

0 / 2,000 characters

Plain text, for example: the second code sample does not compile. Do not include personal information.

You can't do that