본문으로 건너뛰기 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



Frequently Asked Questions (FAQ)

Q. When would I use this in practice?

A. JavaScript functions tutorial: declarations vs expressions, arrow functions, higher-order functions, closures, this, and…

Q. What should I read before this?

A. Follow the previous article or related articles links at the bottom of each post to learn in sequence. See the JavaScript series index for the full picture.

Q. Where can I study this more deeply?

A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.


Other articles related to this topic.


Keywords Covered in This Article (Related Search Terms)

This article covers JavaScript, Functions, Arrow Functions, Callbacks, Closures, Higher-Order Functions.