본문으로 건너뛰기
Previous
Next
JavaScript Functions | Declarations· Arrows

JavaScript Functions | Declarations· Arrows

JavaScript Functions | Declarations· Arrows

이 글의 핵심

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

function add(a, b) {
    return a + b;
}
console.log(add(10, 20));  // 30
greet();  // hoisted
function greet() {
    console.log("Hello!");
}

Function expression

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+)

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:

  1. Concise syntax
  2. Lexical this (inherits from enclosing scope)
  3. No arguments object—use rest parameters (...args)
  4. Not constructible—cannot use new When to use them: array callbacks, short utilities, when lexical this is what you want.

Comparison

DeclarationExpressionArrow
HoistingYesNo*No*
thisdynamicdynamiclexical
argumentsyesyesno
newyesyesno
* Assignments are not hoisted like declarations.

2. Parameters and return values

Default parameters

function greet(name = "guest") {
    return `Hello, ${name}!`;
}
function createArray(length = 10, fill = 0) {
    return Array(length).fill(fill);
}

Rest parameters

function sum(...numbers) {
    return numbers.reduce((acc, num) => acc + num, 0);
}
function introduce(greeting, ...names) {
    return `${greeting}, ${names.join(", ")}!`;
}

Destructuring parameters

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

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

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

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

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.

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

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

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

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

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

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

function processArray(arr, callback) {
    const result = [];
    for (let item of arr) {
        result.push(callback(item));
    }
    return result;
}

Async callbacks

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

The following example demonstrates the concept in javascript:

(function() {
    console.log("IIFE");
})();
(() => {
    console.log("arrow IIFE");
})();
const result = (function() {
    return 10 + 20;
})();

Module-style IIFE

const counterModule = (function() {
    let count = 0;
    return {
        increment() { count++; return count; },
        decrement() { count--; return count; },
        getCount() { return count; }
    };
})();

8. Recursion

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

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

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

const person = {
    name: "Alice",
    greet: () => {
        console.log(this.name);  // wrong: lexical this
    }
};

Closures in loops with var

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

function curry(fn) {
    return function curried(...args) {
        if (args.length >= fn.length) return fn(...args);
        return (...nextArgs) => curried(...args, ...nextArgs);
    };
}

Pipeline

function pipe(...fns) {
    return function(x) {
        return fns.reduce((acc, fn) => fn(acc), x);
    };
}

Summary

Key points

  1. Definitions: declarations hoist; expressions and arrows do not behave like declarations.
  2. Parameters: defaults, rest, destructuring.
  3. Higher-order: pass/return functions; map/filter/reduce.
  4. Closures: encapsulation and memoization.
  5. this: dynamic in ordinary methods; lexical in arrows—choose accordingly.

Best practices

  1. Prefer arrows for short callbacks when this should come from outside.
  2. Write small, pure functions when possible.
  3. Name functions clearly; limit parameter count.

Next steps



자주 묻는 질문 (FAQ)

Q. 이 내용을 실무에서 언제 쓰나요?

A. JavaScript functions tutorial: declarations vs expressions, arrow functions, higher-order functions, closures, this, and… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.

Q. 선행으로 읽으면 좋은 글은?

A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. JavaScript 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.

Q. 더 깊이 공부하려면?

A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.


이 글에서 다루는 키워드 (관련 검색어)

JavaScript, Functions, Arrow Functions, Callbacks, Closures, Higher-Order Functions 등으로 검색하시면 이 글이 도움이 됩니다.