[2026] JavaScript Functions | Declarations, Arrows, Callbacks, and Closures
이 글의 핵심
JavaScript functions tutorial: declarations vs expressions, arrow functions, higher-order functions, closures, this, and callbacks—with patterns for real code.
Introduction
What is a function?
A function is a block of code that performs a task. In JavaScript, functions are first-class values: you can assign them to variables, pass them as arguments, and return them from other functions.
1. Ways to define functions
Function declaration
아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
function add(a, b) {
return a + b;
}
console.log(add(10, 20)); // 30
greet(); // hoisted
function greet() {
console.log("Hello!");
}
Function expression
아래 코드는 javascript를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
const subtract = function(a, b) {
return a - b;
};
const factorial = function fact(n) {
if (n <= 1) return 1;
return n * fact(n - 1);
};
// multiply(); // ReferenceError if called before assignment
const multiply = function(a, b) {
return a * b;
};
Arrow functions (ES6+)
다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
const add = (a, b) => {
return a + b;
};
const add = (a, b) => a + b;
const square = x => x * x;
const greet = () => console.log("Hello!");
const makePerson = (name, age) => ({ name, age });
console.log(makePerson("Alice", 25));
const complexFunc = (a, b) => {
const sum = a + b;
const product = a * b;
return { sum, product };
};
Arrow function notes:
- Concise syntax
- Lexical
this(inherits from enclosing scope) - No
argumentsobject—use rest parameters (...args) - Not constructible—cannot use
newWhen to use them: array callbacks, short utilities, when lexicalthisis what you want.
Comparison
| Declaration | Expression | Arrow | |
|---|---|---|---|
| Hoisting | Yes | No* | No* |
this | dynamic | dynamic | lexical |
arguments | yes | yes | no |
new | yes | yes | no |
| * Assignments are not hoisted like declarations. |
2. Parameters and return values
Default parameters
아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
function greet(name = "guest") {
return `Hello, ${name}!`;
}
function createArray(length = 10, fill = 0) {
return Array(length).fill(fill);
}
Rest parameters
아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
function sum(...numbers) {
return numbers.reduce((acc, num) => acc + num, 0);
}
function introduce(greeting, ...names) {
return `${greeting}, ${names.join(", ")}!`;
}
Destructuring parameters
아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
function printUser({ name, age, city = "Seoul" }) {
console.log(`${name} (${age}, ${city})`);
}
function getMinMax([first, ...rest]) {
return {
min: Math.min(first, ...rest),
max: Math.max(first, ...rest)
};
}
Returning multiple values
아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
function getCoordinates() {
return [10, 20];
}
const [x, y] = getCoordinates();
function getUserInfo() {
return { name: "Alice", age: 25, city: "Seoul" };
}
const { name, age } = getUserInfo();
3. Higher-order functions
Functions as arguments
아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다, 반복문으로 데이터를 처리합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
function repeat(n, action) {
for (let i = 0; i < n; i++) {
action(i);
}
}
repeat(3, console.log);
repeat(3, i => console.log(`iteration ${i}`));
Functions that return functions
아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
function makeMultiplier(factor) {
return function(x) {
return x * factor;
};
}
const double = makeMultiplier(2);
const triple = makeMultiplier(3);
const makeMultiplier = factor => x => x * factor;
Array higher-order methods
아래 코드는 javascript를 사용한 구현 예제입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(x => x * 2);
const evens = numbers.filter(x => x % 2 === 0);
const sum = numbers.reduce((acc, x) => acc + x, 0);
const result = numbers
.filter(x => x % 2 === 0)
.map(x => x * 2)
.reduce((acc, x) => acc + x, 0);
4. Closures
What is a closure?
A closure is a function that remembers variables from the scope where it was created. 아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
function makeCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
const counter2 = makeCounter();
console.log(counter2()); // 1
Private state
다음은 javascript를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
function createBankAccount(initialBalance) {
let balance = initialBalance;
return {
deposit(amount) {
if (amount > 0) balance += amount;
return balance;
},
withdraw(amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
return balance;
}
return null;
},
getBalance() {
return balance;
}
};
}
More examples
아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
function makeAdder(x) {
return y => x + y;
}
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (key in cache) return cache[key];
const result = fn(...args);
cache[key] = result;
return result;
};
}
5. this binding
Ordinary functions
아래 코드는 javascript를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
const person = {
name: "Alice",
greet: function() {
console.log(`Hello, ${this.name}.`);
}
};
person.greet();
const greetFunc = person.greet;
// greetFunc(); // loses `this` in non-strict sloppy mode / undefined in strict
Arrow functions and this
아래 코드는 javascript를 사용한 구현 예제입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
const person = {
name: "Alice",
hobbies: ["reading", "sports", "coding"],
printHobbies2: function() {
this.hobbies.forEach(hobby => {
console.log(`${this.name}'s hobby: ${hobby}`);
});
}
};
person.printHobbies2();
bind, call, apply
아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
const person = { name: "Alice" };
function greet(greeting, punctuation) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
greet.call(person, "Hello", "!");
greet.apply(person, ["Hello", "."]);
const boundGreet = greet.bind(person);
boundGreet("Hi", "~");
6. Callbacks
Basics
아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다, 반복문으로 데이터를 처리합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
function processArray(arr, callback) {
const result = [];
for (let item of arr) {
result.push(callback(item));
}
return result;
}
Async callbacks
다음은 javascript를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
console.log("start");
setTimeout(() => {
console.log("after 2s");
}, 2000);
console.log("end");
setTimeout(() => {
console.log("1s");
setTimeout(() => {
console.log("2s");
setTimeout(() => console.log("3s"), 1000);
}, 1000);
}, 1000);
7. IIFE
아래 코드는 javascript를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
(function() {
console.log("IIFE");
})();
(() => {
console.log("arrow IIFE");
})();
const result = (function() {
return 10 + 20;
})();
Module-style IIFE
아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
const counterModule = (function() {
let count = 0;
return {
increment() { count++; return count; },
decrement() { count--; return count; },
getCount() { return count; }
};
})();
8. Recursion
아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
function sumArray(arr) {
if (arr.length === 0) return 0;
return arr[0] + sumArray(arr.slice(1));
}
9. Practical examples
Utilities: chunk, flatten, unique
다음은 javascript를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
function chunk(arr, size) {
const result = [];
for (let i = 0; i < arr.length; i += size) {
result.push(arr.slice(i, i + size));
}
return result;
}
function flatten(arr) {
return arr.reduce((acc, item) =>
acc.concat(Array.isArray(item) ? flatten(item) : item), []);
}
function unique(arr) {
return [...new Set(arr)];
}
Composition
const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);
const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x);
Debounce and throttle
다음은 javascript를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func(...args), delay);
};
}
function throttle(func, delay) {
let lastCall = 0;
return function(...args) {
const now = Date.now();
if (now - lastCall >= delay) {
lastCall = now;
func(...args);
}
};
}
10. Common mistakes
Arrow functions as methods
아래 코드는 javascript를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
const person = {
name: "Alice",
greet: () => {
console.log(this.name); // wrong: lexical this
}
};
Closures in loops with var
아래 코드는 javascript를 사용한 구현 예제입니다. 반복문으로 데이터를 처리합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
for (var i = 0; i < 3; i++) {
setTimeout(function() { console.log(i); }, 100);
}
for (let i = 0; i < 3; i++) {
setTimeout(function() { console.log(i); }, 100);
}
11. Exercises
Currying
아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다, 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) return fn(...args);
return (...nextArgs) => curried(...args, ...nextArgs);
};
}
Pipeline
아래 코드는 javascript를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
function pipe(...fns) {
return function(x) {
return fns.reduce((acc, fn) => fn(acc), x);
};
}
Summary
Key points
- Definitions: declarations hoist; expressions and arrows do not behave like declarations.
- Parameters: defaults, rest, destructuring.
- Higher-order: pass/return functions;
map/filter/reduce. - Closures: encapsulation and memoization.
- this: dynamic in ordinary methods; lexical in arrows—choose accordingly.
Best practices
- Prefer arrows for short callbacks when
thisshould come from outside. - Write small, pure functions when possible.
- Name functions clearly; limit parameter count.