Langsung ke konten

Pelajaran 2 dari 1011 menit

Functions and scope

Functions package behaviour you can reuse. Scope decides which names a function can see, and closures let it remember them.

Pelajaran ini hanya tersedia dalam bahasa Inggris. Antarmuka halaman tetap dalam bahasa Anda.

Dalam pelajaran ini

  • Write function declarations and arrow functions
  • Use default and rest parameters
  • Explain block scope and closures

Three ways to write a function#

A function takes inputs (parameters), does some work and usually returns a value.

functions.ts
function add(a: number, b: number): number {1  return a + b;}const multiply = function (a: number, b: number): number {2  return a * b;};const subtract = (a: number, b: number): number => a - b;3console.log(add(2, 3), multiply(2, 3), subtract(2, 3)); // 5 6 -1

A declaration. It is hoisted: you can call it above the line where it is written.

A function expression stored in a constant.

An arrow function. With a single expression, the value is returned without writing return.

The : number annotations are TypeScript. Plain JavaScript is the same without them; we keep them because they make the examples easier to read and you will meet TypeScript properly in a later module.

Default and rest parameters#

parameters.ts
function greet(name: string, greeting = "Hello"): string {1  return `${greeting}, ${name}!`;}function sum(...numbers: number[]): number {2  let total = 0;  for (const n of numbers) total += n;  return total;}console.log(greet("Budi")); // "Hello, Budi!"console.log(greet("Budi", "Hi")); // "Hi, Budi!"console.log(sum(1, 2, 3, 4)); // 10

A default value is used when the argument is missing (or undefined).

...numbers collects any number of arguments into an array.

Scope: where a name is visible#

Names created with const and let exist only inside the nearest pair of curly braces, the block.

scope.ts
const message = "outside";if (message.length > 0) {  const inner = "inside";  console.log(message, inner); // both visible here}console.log(inner); // error: inner does not exist out here

Inner blocks can see outer names, never the other way round. This keeps names from leaking and colliding.

Closures: functions that remember#

A function keeps access to the variables that were in scope where it was created, even after the outer function has finished. That bundle is a closure.

counter.ts
function createCounter() {  let count = 0;1  return function increment(): number {2    count += 1;    return count;  };}const next = createCounter();console.log(next(), next(), next()); // 1 2 3

count lives in createCounter's scope. Nothing outside can touch it directly.

increment still sees count after createCounter returned, so each call updates the same variable.

Closures are everywhere: event handlers, timers, React hooks and the debounce helpers you will write later all rely on them.

Arrow function or declaration?

Declarations read well for named, top-level helpers and are hoisted. Arrow functions are shorter for callbacks (items.map((x) => x * 2)) and do not create their own this. Many teams use declarations for top-level functions and arrows for everything passed as an argument.

LatihanTwo independent counters

Call createCounter() twice to make a and b. Call a() twice and b() once. What does each return, and why are they independent?

Tampilkan solusi

a() returns 1 then 2; b() returns 1. Every call to createCounter runs the function again and creates a new count variable, so each returned function closes over its own copy.

Recap#

  • Declarations, expressions and arrow functions all create functions; arrows are compact for callbacks.
  • Default parameters fill gaps; rest parameters collect extras.
  • const/let are block-scoped, and closures let functions remember their surroundings.