자바스크립트 디스트럭처링 (Javascript Destructuring)

자바스크립트 디스트럭처링 (Javascript Destructuring)

열여덟 번째 포스팅까지 다양한 주제를 다루었다면, 이번에는 "문법 및 핵심 개념 (Syntax and Core Concepts)" 범주에 속하는 "디스트럭처링(Destructuring)"에 대해 작성해보려 한다. 디스트럭처링(Destructuring)은 ES6에서 도입된 문법으로, 배열(Array)과 객체(Object)에서 값을 추출하는 방식을 간소화한다.


디스트럭처링(Destructuring)은 복잡한 데이터 구조(Data Structure)에서 필요한 값만 쉽게 가져오며, 코드 가독성(Readability)을 높인다. 이번 포스팅에서는 디스트럭처링(Destructuring)의 개념, 배열 디스트럭처링(Array Destructuring), 객체 디스트럭처링(Object Destructuring), 활용 방법(Usage), 그리고 실습 예제(Practice Example)를 작성해볼 예정이다.


디스트럭처링(Destructuring)은 자바스크립트(Javascript)의 데이터 처리(Data Processing)를 이해하는 데 필수적이다. 콘솔(Console) 또는 HTML 파일에서 예제를 실행하며 디스트럭처링(Destructuring)의 동작을 체감할 수 있다.


디스트럭처링의 개념 (Concept of Destructuring)

디스트럭처링(Destructuring)은 배열(Array)이나 객체(Object)의 요소를 변수(Variable)로 분해한다. 기존에는 인덱스(Index)나 속성 이름(Property Name)으로 값을 하나씩 가져왔지만, 디스트럭처링(Destructuring)은 이를 간결하게 처리한다.

다음은 기본적인 디스트럭처링(Destructuring) 예제이다:

const arr = [1, 2, 3];
const [a, b, c] = arr;
console.log(a, b, c); // 1 2 3

const obj = { x: 10, y: 20 };
const { x, y } = obj;
console.log(x, y); // 10 20
        

위 예제는 배열(Array)과 객체(Object)를 분해한다.

디스트럭처링(Destructuring)은 코드 간결성(Simplicity)과 효율성(Efficiency)을 높인다. 이는 데이터 조작(Data Manipulation)에서 유용하다.


배열 디스트럭처링 (Array Destructuring)

배열 디스트럭처링(Array Destructuring)은 배열(Array) 요소를 변수(Variable)로 추출한다.


1. 기본 분해 (Basic Destructuring)

순서대로 값을 할당한다:

const [first, second] = [10, 20];
console.log(first); // 10
console.log(second); // 20
        

2. 나머지 요소 (Rest Elements)

...로 나머지를 배열(Array)로 받는다:

const [head, ...rest] = [1, 2, 3, 4];
console.log(head); // 1
console.log(rest); // [2, 3, 4]
        

예제: 배열 분해 (Array Destructuring Example)

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>배열 디스트럭처링 (Array Destructuring)</title>
</head>
<body>
    <button id="btn">분해</button>
    <div id="result"></div>
    <script>
        const numbers = [10, 20, 30, 40];
        const [first, second, ...others] = numbers;

        const btn = document.getElementById('btn');
        const result = document.getElementById('result');

        btn.addEventListener('click', () => {
            result.textContent = `첫 번째: ${first}, 두 번째: ${second}, 나머지: ${others}`;
        });
    </script>
</body>
</html>
        

이 예제는 배열(Array)을 분해한다.


객체 디스트럭처링 (Object Destructuring)

객체 디스트럭처링(Object Destructuring)은 속성(Property)을 변수(Variable)로 추출한다.


1. 기본 분해 (Basic Destructuring)

속성 이름(Property Name)으로 값을 할당한다:

const { name, age } = { name: '홍길동', age: 25 };
console.log(name); // "홍길동"
console.log(age); // 25
        

2. 별칭 사용 (Alias Usage)

새로운 변수 이름(Variable Name)을 지정한다:

const { name: userName, age: userAge } = { name: '김유신', age: 30 };
console.log(userName); // "김유신"
console.log(userAge); // 30
        

예제: 객체 분해 (Object Destructuring Example)

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>객체 디스트럭처링 (Object Destructuring)</title>
</head>
<body>
    <button id="btn">정보 표시</button>
    <div id="result"></div>
    <script>
        const person = { name: '이순신', age: 40, city: '서울' };
        const { name: pName, age: pAge } = person;

        const btn = document.getElementById('btn');
        const result = document.getElementById('result');

        btn.addEventListener('click', () => {
            result.textContent = `${pName}, ${pAge}세`;
        });
    </script>
</body>
</html>
        

이 예제는 객체(Object)를 분해한다.


디스트럭처링 활용 (Usage of Destructuring)

디스트럭처링(Destructuring)은 다양한 상황에서 활용된다.


1. 함수 매개변수 (Function Parameters)

매개변수(Parameter)를 분해한다:

function printInfo({ name, age }) {
    console.log(`${name}, ${age}`);
}
printInfo({ name: '홍길동', age: 25 }); // "홍길동, 25"
        

2. 중첩 분해 (Nested Destructuring)

중첩 객체(Nested Object)를 분해한다:

const data = { user: { name: '김유신', info: { age: 30 } } };
const { user: { name, info: { age } } } = data;
console.log(name, age); // "김유신", 30
        

예제: 함수 활용 (Function Usage Example)

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>함수 디스트럭처링 (Function Destructuring)</title>
</head>
<body>
    <button id="btn">표시</button>
    <div id="result"></div>
    <script>
        function showUser({ name, age }) {
            return `${name}, ${age}세`;
        }
        const user = { name: '이순신', age: 40 };

        const btn = document.getElementById('btn');
        const result = document.getElementById('result');

        btn.addEventListener('click', () => {
            result.textContent = showUser(user);
        });
    </script>
</body>
</html>
        

이 예제는 함수 매개변수(Parameter)를 분해한다.


실습 예제: 디스트럭처링 관리 (Destructuring Management Example)

디스트럭처링(Destructuring)을 활용한 관리 예제이다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>디스트럭처링 관리 (Destructuring Management)</title>
    <style>
        #itemList {
            list-style-type: none;
            padding: 0;
        }
        #itemList li {
            padding: 5px;
            background: #f0f0f0;
            margin: 5px 0;
        }
    </style>
</head>
<body>
    <input type="text" id="titleInput" placeholder="제목">
    <input type="text" id="descInput" placeholder="설명">
    <button id="addBtn">추가</button>
    <ul id="itemList"></ul>
    <script>
        const items = [];
        const titleInput = document.getElementById('titleInput');
        const descInput = document.getElementById('descInput');
        const addBtn = document.getElementById('addBtn');
        const itemList = document.getElementById('itemList');

        function renderItems() {
            itemList.innerHTML = items.map(({ title, desc }) => `
                <li>${title} - ${desc}</li>
            `).join('');
        }

        addBtn.addEventListener('click', () => {
            if (titleInput.value && descInput.value) {
                items.push({ title: titleInput.value, desc: descInput.value });
                renderItems();
                titleInput.value = '';
                descInput.value = '';
            }
        });
    </script>
</body>
</html>
        

이 예제는 디스트럭처링(Destructuring)으로 항목을 관리한다.


Destructuring Example

실무에서의 디스트럭처링 (Destructuring in Practice)

실무에서는 API 데이터 처리(API Data Processing)에 활용한다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>API 디스트럭처링 (API Destructuring)</title>
</head>
<body>
    <button id="fetchBtn">데이터 표시</button>
    <div id="result"></div>
    <script>
        const fetchBtn = document.getElementById('fetchBtn');
        const result = document.getElementById('result');

        fetchBtn.addEventListener('click', async () => {
            const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
            const { name, email, phone } = await response.json();
            result.textContent = `${name}, ${email}, ${phone}`;
        });
    </script>
</body>
</html>
        

이 예제는 API 데이터(API Data)를 분해한다.


주의할 점 (Cautions)

디스트럭처링(Destructuring)은 값이 없는 경우 undefined를 반환한다. 중첩 구조(Nested Structure)는 가독성(Readability)을 고려한다. 변수 이름(Variable Name) 충돌을 방지한다.


결론 (Conclusion)

디스트럭처링(Destructuring)의 선언, 활용을 학습하며 실습 예제를 통해 알아보았다. 다음 포스팅에서는 스프레드와 레스트 연산자(Spread and Rest Operators)에 대해 작성해볼 예정이다.

자바스크립트 템플릿 리터럴

자바스크립트 템플릿 리터럴

열일곱 번째 포스팅까지 다양한 주제를 다루었다면, 이번에는 "문법 및 핵심 개념" 범주에 속하는 "템플릿 리터럴"에 대해 작성해보려 한다. 템플릿 리터럴(Template Literals)은 ES6에서 도입된 문자열 처리 문법으로, 문자열 생성과 다중 줄 표현을 간소화한다.


템플릿 리터럴은 변수 삽입과 표현식 평가를 지원하며, 기존 문자열 연결 방식을 간편하게 대체한다. 이번 포스팅에서는 템플릿 리터럴의 개념, 기본 사용법, 태그드 템플릿, 활용 방법, 그리고 실습 예제를 작성해볼 예정이다.


템플릿 리터럴은 자바스크립트의 문자열 처리를 이해하는 데 필수적이다. 콘솔 또는 HTML 파일에서 예제를 실행하며 템플릿 리터럴의 동작을 체감할 수 있다.


템플릿 리터럴의 개념

템플릿 리터럴은 백틱(`)으로 감싸는 문자열이다. 기존 문자열은 작은따옴표('')나 큰따옴표("")로 정의되며, 연결 시 + 연산자를 사용한다. 반면 템플릿 리터럴은 변수와 표현식을 직접 삽입하며, 다중 줄 문자열을 지원한다.

다음은 기본적인 템플릿 리터럴 예제이다:

const name = '홍길동';
const greeting = `안녕하세요, ${name}님!`;
console.log(greeting); // "안녕하세요, 홍길동님!"
        

위 예제는 템플릿 리터럴로 문자열을 생성한다.

템플릿 리터럴은 코드 가독성과 편의성을 높인다. 이는 문자열 조작에서 필수적이다.


기본 사용법

템플릿 리터럴은 ` 백틱으로 선언한다.


1. 변수 삽입

${}로 변수를 삽입한다:

const age = 30;
const message = `저는 ${age}세입니다.`;
console.log(message); // "저는 30세입니다."
        

2. 다중 줄 문자열

줄바꿈을 직접 표현한다:

const poem = `
    안녕하세요
    반갑습니다
`;
console.log(poem);
// "
//     안녕하세요
//     반갑습니다
// "
        

예제: 기본 사용

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>템플릿 리터럴 기본</title>
</head>
<body>
    <button id="btn">메시지 표시</button>
    <div id="result"></div>
    <script>
        const name = '김유신';
        const age = 25;
        const message = `이름: ${name}
나이: ${age}세`;

        const btn = document.getElementById('btn');
        const result = document.getElementById('result');

        btn.addEventListener('click', () => {
            result.textContent = message;
        });
    </script>
</body>
</html>
        

이 예제는 다중 줄 메시지를 표시한다.


태그드 템플릿

태그드 템플릿은 함수를 통해 템플릿 리터럴을 처리한다).


1. 태그 함수 정의

문자열과 표현식을 인자로 받는다:

function tag(strings, ...values) {
    return strings[0] + values[0].toUpperCase() + strings[1];
}
const name = '홍길동';
const result = tag`안녕, ${name}님!`;
console.log(result); // "안녕, 홍길동님!"
        

2. 태그드 활용

형식을 커스터마이징한다:

function highlight(strings, ...values) {
    return strings.reduce((acc, str, i) => {
        return acc + str + (values[i] ? `<strong>${values[i]}</strong>` : '');
    }, '');
}
const text = highlight`이름: ${name}, 나이: ${age}`;
console.log(text); // "이름: <strong>홍길동</strong>, 나이: <strong>25</strong>"
        

예제: 태그드 템플릿

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>태그드 템플릿</title>
</head>
<body>
    <button id="btn">강조 표시</button>
    <div id="result"></div>
    <script>
        function bold(strings, ...values) {
            return strings.reduce((acc, str, i) => {
                return acc + str + (values[i] ? `<b>${values[i]}</b>` : '');
            }, '');
        }
        const name = '김유신';
        const age = 30;

        const btn = document.getElementById('btn');
        const result = document.getElementById('result');

        btn.addEventListener('click', () => {
            result.innerHTML = bold`이름: ${name}, 나이: ${age}세`;
        });
    </script>
</body>
</html>
        

이 예제는 태그드 템플릿으로 강조한다.


템플릿 활용

템플릿 리터럴은 다양한 상황에서 활용된다.


1. 동적 HTML 생성

HTML을 생성한다:

const items = ['사과', '바나나'];
const list = `
    <ul>
        ${items.map(item => `<li>${item}</li>`).join('')}
    </ul>
`;
console.log(list);
// "
//     <ul>
//         <li>사과</li>
//         <li>바나나</li>
//     </ul>
// "
        

2. 문자열 포매팅

복잡한 문자열을 포맷한다:

const price = 1000;
const tax = 0.1;
const total = `총액: ${price + price * tax}원`;
console.log(total); // "총액: 1100원"
        

예제: HTML 생성

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>HTML 생성</title>
</head>
<body>
    <button id="btn">목록 생성</button>
    <div id="result"></div>
    <script>
        const fruits = ['사과', '오렌지', '포도'];
        const btn = document.getElementById('btn');
        const result = document.getElementById('result');

        btn.addEventListener('click', () => {
            const html = `
                <ul>
                    ${fruits.map(fruit => `<li>${fruit}</li>`).join('')}
                </ul>
            `;
            result.innerHTML = html;
        });
    </script>
</body>
</html>
        

이 예제는 목록을 생성한다.


실습 예제: 템플릿 관리

템플릿 리터럴을 활용한 관리 예제이다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>템플릿 관리</title>
    <style>
        #userList {
            list-style-type: none;
            padding: 0;
        }
        #userList li {
            padding: 5px;
            background: #f0f0f0;
            margin: 5px 0;
        }
    </style>
</head>
<body>
    <input type="text" id="nameInput" placeholder="이름">
    <input type="number" id="ageInput" placeholder="나이">
    <button id="addBtn">추가</button>
    <ul id="userList"></ul>
    <script>
        const users = [];
        const nameInput = document.getElementById('nameInput');
        const ageInput = document.getElementById('ageInput');
        const addBtn = document.getElementById('addBtn');
        const userList = document.getElementById('userList');

        function renderUsers() {
            userList.innerHTML = `
                ${users.map(user => `
                    <li>${user.name}, ${user.age}세</li>
                `).join('')}
            `;
        }

        addBtn.addEventListener('click', () => {
            if (nameInput.value && ageInput.value) {
                users.push({
                    name: nameInput.value,
                    age: parseInt(ageInput.value)
                });
                renderUsers();
                nameInput.value = '';
                ageInput.value = '';
            }
        });
    </script>
</body>
</html>
        

이 예제는 사용자 목록을 관리한다.


Template Literal Example

실무에서의 템플릿 리터럴

실무에서는 동적 콘텐츠에 활용한다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>동적 콘텐츠</title>
</head>
<body>
    <button id="fetchBtn">데이터 표시</button>
    <div id="result"></div>
    <script>
        const fetchBtn = document.getElementById('fetchBtn');
        const result = document.getElementById('result');

        fetchBtn.addEventListener('click', async () => {
            const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
            const data = await response.json();
            result.innerHTML = `
                <h3>${data.name}</h3>
                <p>이메일: ${data.email}</p>
                <p>전화: ${data.phone}</p>
            `;
        });
    </script>
</body>
</html>
        

이 예제는 API 데이터를 표시한다.


주의할 점

템플릿 리터럴은 XSS 공격에 주의한다. 다중 줄 문자열의 공백을 관리한다. 복잡한 로직은 함수로 분리한다.


결론

템플릿 리터럴의 선언, 태그드를 학습하며 실습 예제를 통해 알아보았다. 다음 포스팅에서는 디스트럭처링에 대해 작성해볼 예정이다.

자바스크립트 모듈

자바스크립트 모듈

열여섯 번째 포스팅까지 다양한 주제를 다루었다면, 이번에는 "문법 및 핵심 개념" 범주에 속하는 "모듈"에 대해 작성해보려 한다. 모듈(Module)은 ES6에서 도입된 코드 분리 및 재사용을 위한 문법으로, 자바스크립트 애플리케이션의 구조를 체계적으로 관리한다.


모듈은 자바스크립트에서 코드를 파일 단위로 분할하며, 외부에서 필요한 기능만 노출한다. 이번 포스팅에서는 모듈의 개념, 선언 및 내보내기, 가져오기 방식, 활용 방법, 그리고 실습 예제를 작성해볼 예정이다.


모듈은 자바스크립트의 유지보수를 이해하는 데 필수적이다. 콘솔 또는 HTML 파일에서 예제를 실행하며 모듈의 동작을 체감할 수 있다.


모듈의 개념

모듈은 독립적인 코드 단위를 의미한다. 자바스크립트에서 모듈은 ES6 이전의 IIFE(즉시 실행 함수)나 CommonJS 방식을 대체하여, 표준화된 방식으로 코드를 분리한다. 모듈은 변수, 함수, 클래스를 캡슐화하며, 외부로 내보내기(export)와 가져오기(import)를 통해 관리한다.

다음은 기본적인 모듈 예제이다:

// utils.js
export function sayHello(name) {
    return `안녕, ${name}입니다.`;
}

// main.js
import { sayHello } from './utils.js';
console.log(sayHello('홍길동')); // "안녕, 홍길동입니다."
        

위 예제는 모듈을 정의하고 사용한다.

모듈은 코드의 재사용성과 가독성을 높인다. 이는 대규모 애플리케이션 개발에서 필수적이다.


모듈 선언과 내보내기

모듈은 export 키워드로 내보낸다.


1. 명명된 내보내기

개별 항목을 내보낸다:

// math.js
export function add(a, b) {
    return a + b;
}
export const PI = 3.14;

// app.js
import { add, PI } from './math.js';
console.log(add(2, 3)); // 5
console.log(PI); // 3.14
        

2. 기본 내보내기

단일 항목을 기본으로 내보낸다:

// user.js
export default class User {
    constructor(name) {
        this.name = name;
    }
    greet() {
        return `안녕, ${this.name}`;
    }
}

// app.js
import User from './user.js';
const user = new User('김유신');
console.log(user.greet()); // "안녕, 김유신"
        

예제: 내보내기 활용

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>모듈 내보내기</title>
    <script type="module">
        // 모듈로 사용하려면 type="module" 필요
        import { greet } from './greet.js';
        document.getElementById('btn').addEventListener('click', () => {
            document.getElementById('result').textContent = greet('홍길동');
        });
    </script>
</head>
<body>
    <button id="btn">인사</button>
    <div id="result"></div>
</body>
</html>

// greet.js
<script type="module">
export function greet(name) {
    return `안녕하세요, ${name}님!`;
}
</script>
        

이 예제는 명명된 내보내기를 사용한다. (참고: 실제 실행은 로컬 서버 필요)


모듈 가져오기

모듈은 import 키워드로 가져온다.


1. 명명된 가져오기

특정 항목을 가져온다:

import { multiply, divide } from './math.js';
        

2. 기본 가져오기

기본 내보내기 항목을 가져온다:

import User from './user.js';
        

3. 전체 가져오기

*로 모든 항목을 가져온다:

import * as utils from './utils.js';
console.log(utils.add(1, 2)); // 3
        

예제: 가져오기 방식

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>모듈 가져오기</title>
    <script type="module">
        import * as calc from './calc.js';
        document.getElementById('addBtn').addEventListener('click', () => {
            document.getElementById('result').textContent = calc.add(5, 3);
        });
        document.getElementById('subBtn').addEventListener('click', () => {
            document.getElementById('result').textContent = calc.subtract(5, 3);
        });
    </script>
</head>
<body>
    <button id="addBtn">더하기</button>
    <button id="subBtn">빼기</button>
    <div id="result"></div>
</body>
</html>

// calc.js
<script type="module">
export function add(a, b) {
    return a + b;
}
export function subtract(a, b) {
    return a - b;
}
</script>
        

이 예제는 전체 가져오기를 사용한다.


모듈 활용

모듈은 다양한 상황에서 활용된다.


1. 유틸리티 모듈

공통 기능을 모듈화한다:

// stringUtils.js
export function capitalize(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
}

// app.js
import { capitalize } from './stringUtils.js';
console.log(capitalize('hello')); // "Hello"
        

2. 데이터 모듈

데이터를 관리한다:

// data.js
export const config = {
    apiKey: 'abc123',
    baseUrl: 'https://api.example.com'
};

// app.js
import { config } from './data.js';
console.log(config.apiKey); // "abc123"
        

예제: 모듈 활용

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>모듈 활용</title>
    <script type="module">
        import { formatDate } from './dateUtils.js';
        document.getElementById('btn').addEventListener('click', () => {
            document.getElementById('result').textContent = formatDate(new Date());
        });
    </script>
</head>
<body>
    <button id="btn">날짜 표시</button>
    <div id="result"></div>
</body>
</html>

// dateUtils.js
<script type="module">
export function formatDate(date) {
    return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
}
</script>
        

이 예제는 날짜 형식을 모듈화한다.


실습 예제: 모듈 관리

모듈을 활용한 관리 예제이다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>모듈 관리</title>
    <style>
        #taskList {
            list-style-type: none;
            padding: 0;
        }
        #taskList li {
            padding: 5px;
            background: #f0f0f0;
            margin: 5px 0;
        }
    </style>
    <script type="module">
        import { TaskManager } from './taskManager.js';
        const manager = new TaskManager();
        const input = document.getElementById('input');
        const addBtn = document.getElementById('addBtn');

        addBtn.addEventListener('click', () => {
            if (input.value) {
                manager.addTask(input.value);
                input.value = '';
            }
        });
    </script>
</head>
<body>
    <input type="text" id="input" placeholder="할 일 입력">
    <button id="addBtn">추가</button>
    <ul id="taskList"></ul>
</body>
</html>

// taskManager.js
<script type="module">
export class TaskManager {
    constructor() {
        this.tasks = [];
    }
    addTask(task) {
        this.tasks.push(task);
        this.render();
    }
    render() {
        const list = document.getElementById('taskList');
        list.innerHTML = '';
        this.tasks.forEach((task, index) => {
            const li = document.createElement('li');
            li.textContent = `${index + 1}. ${task}`;
            list.appendChild(li);
        });
    }
}
</script>
        

이 예제는 모듈로 할 일을 관리한다.


Module Example

실무에서의 모듈

실무에서는 API 호출을 모듈화한다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>API 모듈</title>
    <script type="module">
        import { fetchData } from './api.js';
        document.getElementById('fetchBtn').addEventListener('click', async () => {
            const data = await fetchData('https://jsonplaceholder.typicode.com/users/1');
            document.getElementById('result').textContent = JSON.stringify(data, null, 2);
        });
    </script>
</head>
<body>
    <button id="fetchBtn">데이터 가져오기</button>
    <div id="result"></div>
</body>
</html>

// api.js
<script type="module">
export async function fetchData(url) {
    const response = await fetch(url);
    return await response.json();
}
</script>
        

이 예제는 API 호출을 모듈화한다.


주의할 점

모듈은 로컬 실행 시 서버가 필요하다. 이름 충돌을 방지한다. 비동기 모듈 로딩을 고려한다.


결론

모듈의 선언, 내보내기를 학습하며 실습 예제를 통해 알아보았다. 다음 포스팅에서는 템플릿 리터럴에 대해 작성해볼 예정이다.

자바스크립트 클래스

자바스크립트 클래스

열다섯 번째 포스팅까지 다양한 주제를 다루었다면, 이번에는 "문법 및 핵심 개념" 범주에 속하는 "클래스"에 대해 작성해보려 한다. 클래스(Class)는 ES6에서 도입된 객체 지향 프로그래밍 문법으로, 객체 생성과 상속을 체계적으로 관리한다.


클래스는 자바스크립트에서 객체 기반 코드를 구조화하며, 기존 프로토타입 기반 상속을 간소화한다. 이번 포스팅에서는 클래스의 개념, 선언 및 사용, 메서드와 속성, 상속, 그리고 실습 예제를 작성해볼 예정이다.


클래스는 자바스크립트의 객체 지향 프로그래밍을 이해하는 데 필수적이다. 콘솔 또는 HTML 파일에서 예제를 실행하며 클래스의 동작을 체감할 수 있다.


클래스의 개념

클래스는 객체를 생성하기 위한 템플릿이다. 자바스크립트에서 클래스는 ES6 이전의 프로토타입 기반 객체 생성을 더 직관적인 문법으로 대체한다. 클래스는 속성(프로퍼티)과 메서드를 정의하며, 이를 기반으로 인스턴스를 생성한다.

다음은 기본적인 클래스 예제이다:

class Person {
    constructor(name) {
        this.name = name;
    }
    sayHello() {
        console.log(`안녕, ${this.name}입니다.`);
    }
}
const person = new Person('홍길동');
person.sayHello(); // "안녕, 홍길동입니다."
        

위 예제는 클래스를 정의하고 인스턴스를 생성한다.

클래스는 객체 지향 프로그래밍의 캡슐화와 상속을 지원한다. 이는 코드의 재사용성과 가독성을 강화한다.


클래스 선언과 사용

클래스는 class 키워드로 선언한다.


1. 클래스 선언

기본 구조는 다음과 같다:

class Car {
    constructor(brand) {
        this.brand = brand;
    }
    drive() {
        console.log(`${this.brand}가 운전됩니다.`);
    }
}
const myCar = new Car('현대');
myCar.drive(); // "현대가 운전됩니다."
        

2. 생성자

constructor는 인스턴스 초기화를 담당한다:

class Book {
    constructor(title, author) {
        this.title = title;
        this.author = author;
    }
    getInfo() {
        return `${this.title} - ${this.author}`;
    }
}
const book = new Book('자바스크립트', '김유신');
console.log(book.getInfo()); // "자바스크립트 - 김유신"
        

예제: 클래스 기본 사용

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>클래스 기본</title>
</head>
<body>
    <button id="btn">정보 표시</button>
    <div id="result"></div>
    <script>
        class User {
            constructor(name, age) {
                this.name = name;
                this.age = age;
            }
            showInfo() {
                return `${this.name}, ${this.age}세`;
            }
        }
        const user = new User('홍길동', 30);
        const btn = document.getElementById('btn');
        const result = document.getElementById('result');

        btn.addEventListener('click', () => {
            result.textContent = user.showInfo();
        });
    </script>
</body>
</html>
        

이 예제는 클래스 인스턴스의 정보를 표시한다.


메서드와 속성

클래스는 메서드와 속성을 정의한다.


1. 인스턴스 메서드

인스턴스에 속한다:

class Counter {
    constructor() {
        this.count = 0;
    }
    increment() {
        this.count++;
        return this.count;
    }
}
const counter = new Counter();
console.log(counter.increment()); // 1
        

2. 정적 메서드

static으로 클래스 자체에 속한다:

class MathUtil {
    static add(a, b) {
        return a + b;
    }
}
console.log(MathUtil.add(5, 3)); // 8
        

예제: 메서드 활용

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>메서드 활용</title>
</head>
<body>
    <button id="incBtn">증가</button>
    <button id="addBtn">더하기</button>
    <div id="result">0</div>
    <script>
        class Calculator {
            constructor() {
                this.value = 0;
            }
            increment() {
                this.value++;
                return this.value;
            }
            static add(a, b) {
                return a + b;
            }
        }
        const calc = new Calculator();
        const incBtn = document.getElementById('incBtn');
        const addBtn = document.getElementById('addBtn');
        const result = document.getElementById('result');

        incBtn.addEventListener('click', () => {
            result.textContent = calc.increment();
        });

        addBtn.addEventListener('click', () => {
            result.textContent = Calculator.add(parseInt(result.textContent), 10);
        });
    </script>
</body>
</html>
        

이 예제는 인스턴스와 정적 메서드를 결합한다.


클래스 상속

클래스는 extends로 상속한다.


1. 기본 상속

부모 클래스를 확장한다:

class Animal {
    constructor(name) {
        this.name = name;
    }
    speak() {
        console.log(`${this.name}가 소리를 냅니다.`);
    }
}
class Dog extends Animal {
    bark() {
        console.log(`${this.name}가 짖습니다.`);
    }
}
const dog = new Dog('멍멍이');
dog.speak(); // "멍멍이가 소리를 냅니다."
dog.bark(); // "멍멍이가 짖습니다."
        

2. super 호출

super로 부모 생성자를 호출한다:

class Cat extends Animal {
    constructor(name, color) {
        super(name);
        this.color = color;
    }
    describe() {
        console.log(`${this.name}는 ${this.color}색입니다.`);
    }
}
const cat = new Cat('야옹이', '검정');
cat.describe(); // "야옹이는 검정색입니다."
        

예제: 상속 활용

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>클래스 상속</title>
</head>
<body>
    <button id="speakBtn">소리</button>
    <button id="barkBtn">짖기</button>
    <div id="result"></div>
    <script>
        class Animal {
            constructor(name) {
                this.name = name;
            }
            speak() {
                return `${this.name}가 소리를 냅니다.`;
            }
        }
        class Dog extends Animal {
            bark() {
                return `${this.name}가 짖습니다.`;
            }
        }
        const dog = new Dog('멍멍이');
        const speakBtn = document.getElementById('speakBtn');
        const barkBtn = document.getElementById('barkBtn');
        const result = document.getElementById('result');

        speakBtn.addEventListener('click', () => {
            result.textContent = dog.speak();
        });

        barkBtn.addEventListener('click', () => {
            result.textContent = dog.bark();
        });
    </script>
</body>
</html>
        

이 예제는 상속을 활용한다.


실습 예제: 클래스 관리

클래스를 활용한 관리 예제이다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>클래스 관리</title>
    <style>
        #itemList {
            list-style-type: none;
            padding: 0;
        }
        #itemList li {
            padding: 5px;
            background: #f0f0f0;
            margin: 5px 0;
        }
    </style>
</head>
<body>
    <input type="text" id="input" placeholder="항목 입력">
    <button id="addBtn">추가</button>
    <ul id="itemList"></ul>
    <script>
        class ItemManager {
            constructor() {
                this.items = [];
            }
            addItem(item) {
                this.items.push(item);
                this.render();
            }
            render() {
                const list = document.getElementById('itemList');
                list.innerHTML = '';
                this.items.forEach((item, index) => {
                    const li = document.createElement('li');
                    li.textContent = `${index + 1}. ${item}`;
                    list.appendChild(li);
                });
            }
        }
        const manager = new ItemManager();
        const input = document.getElementById('input');
        const addBtn = document.getElementById('addBtn');

        addBtn.addEventListener('click', () => {
            if (input.value) {
                manager.addItem(input.value);
                input.value = '';
            }
        });
    </script>
</body>
</html>
        

이 예제는 클래스로 항목을 관리한다.


Class Example

실무에서의 클래스

실무에서는 데이터 모델에 활용한다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>데이터 모델</title>
</head>
<body>
    <button id="fetchBtn">데이터 가져오기</button>
    <div id="result"></div>
    <script>
        class DataFetcher {
            constructor(url) {
                this.url = url;
            }
            async fetchData() {
                const response = await fetch(this.url);
                const data = await response.json();
                return data;
            }
            display(data) {
                result.textContent = JSON.stringify(data, null, 2);
            }
        }
        const fetcher = new DataFetcher('https://jsonplaceholder.typicode.com/users/1');
        const fetchBtn = document.getElementById('fetchBtn');
        const result = document.getElementById('result');

        fetchBtn.addEventListener('click', async () => {
            const data = await fetcher.fetchData();
            fetcher.display(data);
        });
    </script>
</body>
</html>
        

이 예제는 클래스로 데이터를 관리한다.


주의할 점

클래스는 프로토타입 기반이다. 상속 시 super 호출을 잊지 않는다. 정적 메서드는 인스턴스에서 호출 불가하다.


결론

클래스의 선언, 상속을 학습하며 실습 예제를 통해 알아보았다. 다음 포스팅에서는 모듈에 대해 작성해볼 예정이다.

자바스크립트 this 바인딩

자바스크립트 this 바인딩

열네 번째 포스팅에서 클로저를 다루었다면, 이번에는 "문법 및 핵심 개념" 범주에 속하는 "this 바인딩"에 대해 알아보려 한다. this 바인딩은 자바스크립트에서 함수 호출 시 this 키워드가 참조하는 객체를 결정하며, 객체 지향 프로그래밍과 함수 실행에 핵심적인 역할을 한다.


this 바인딩은 호출 방식에 따라 달라지며, 이해하지 못하면 오류가 발생한다. 이번 포스팅에서는 this 바인딩의 개념, 바인딩 규칙, 제어 방법, 그리고 실습 예제를 상세히 다룬다.


클로저와 함께 this 바인딩은 자바스크립트의 고급 문법을 이해하는 데 필수적이다. 콘솔에서 예제를 실행하며 this의 동작을 체감할 수 있다.


this 바인딩의 개념

this는 함수 호출 시 결정되는 동적 컨텍스트이다. 자바스크립트에서 this는 함수가 호출되는 방식에 따라 참조하는 객체가 달라진다. 다음은 기본적인 this 예제이다:

function sayThis() {
    console.log(this);
}
sayThis(); // Window (브라우저 환경)
        

위 예제는 전역 호출 시 this가 전역 객체를 참조한다.

this는 객체 지향 프로그래밍에서 객체의 속성과 메서드를 연결한다. 호출 방식에 따라 동작이 달라지므로 규칙을 이해해야 한다.


this 바인딩 규칙

this 바인딩은 네 가지 규칙에 따라 결정된다.


1. 기본 바인딩

함수가 독립적으로 호출되면 전역 객체를 참조한다:

function basic() {
    console.log(this);
}
basic(); // Window
        

2. 암시적 바인딩

객체의 메서드로 호출되면 해당 객체를 참조한다:

const obj = {
    name: '객체',
    say: function() {
        console.log(this.name);
    }
};
obj.say(); // "객체"
        

3. 명시적 바인딩

call, apply, bindthis를 지정한다:

function explicit() {
    console.log(this.value);
}
const data = { value: '데이터' };
explicit.call(data); // "데이터"
        

4. new 바인딩

생성자 함수로 호출되면 새 객체를 참조한다:

function NewObj() {
    this.name = '새 객체';
}
const instance = new NewObj();
console.log(instance.name); // "새 객체"
        

예제: 바인딩 비교

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>this 바인딩</title>
</head>
<body>
    <script>
        function showThis() {
            console.log(this);
        }
        showThis(); // Window

        const obj = { show: showThis };
        obj.show(); // obj

        showThis.call({ value: '명시적' }); // { value: "명시적" }

        const newInstance = new showThis(); // showThis {}
    </script>
</body>
</html>
        

이 예제는 네 가지 바인딩을 확인한다.


this 바인딩 제어

this 바인딩은 명시적으로 제어한다.


1. call과 apply

callapply로 this를 변경한다:

function greet(greeting) {
    console.log(`${greeting}, ${this.name}`);
}
const person1 = { name: '홍길동' };
const person2 = { name: '김유신' };
greet.call(person1, '안녕'); // "안녕, 홍길동"
greet.apply(person2, ['안녕']); // "안녕, 김유신"
        

2. bind

bind로 고정된 함수를 생성한다:

const boundGreet = greet.bind(person1);
boundGreet('안녕'); // "안녕, 홍길동"
        

예제: this 제어

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>this 제어</title>
</head>
<body>
    <button id="btn1">버튼 1</button>
    <button id="btn2">버튼 2</button>
    <div id="result"></div>
    <script>
        function showName() {
            result.textContent = this.name;
        }
        const obj1 = { name: '첫 번째' };
        const obj2 = { name: '두 번째' };
        const boundShow1 = showName.bind(obj1);
        const boundShow2 = showName.bind(obj2);

        const btn1 = document.getElementById('btn1');
        const btn2 = document.getElementById('btn2');
        const result = document.getElementById('result');

        btn1.addEventListener('click', boundShow1);
        btn2.addEventListener('click', boundShow2);
    </script>
</body>
</html>
        

이 예제는 bind로 this를 제어한다.


실습 예제: this와 클로저

this와 클로저를 결합한 예제이다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>this와 클로저</title>
</head>
<body>
    <button id="btn">증가</button>
    <div id="count">0</div>
    <script>
        const btn = document.getElementById('btn');
        const count = document.getElementById('count');
        const counter = (function() {
            var num = 0;
            return {
                increment: function() {
                    num++;
                    this.display(num);
                },
                display: function(value) {
                    count.textContent = value;
                }
            };
        })();

        btn.addEventListener('click', () => counter.increment.call(counter));
    </script>
</body>
</html>
        

이 예제는 클로저와 this를 결합한다.


This Binding Example

실무에서의 this 바인딩

실무에서는 이벤트 핸들러에서 this를 관리한다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>이벤트 this</title>
</head>
<body>
    <button id="btn">클릭</button>
    <div id="log"></div>
    <script>
        const obj = {
            name: '객체',
            handleClick: function() {
                log.textContent = this.name;
            }
        };
        const btn = document.getElementById('btn');
        const log = document.getElementById('log');
        btn.addEventListener('click', obj.handleClick.bind(obj));
    </script>
</body>
</html>
        

이 예제는 이벤트에서 this를 고정한다.


주의할 점

this는 호출 시점에 결정되므로 예측한다. 화살표 함수는 this를 바인딩하지 않는다. 명시적 바인딩을 적절히 사용한다.


결론

this의 규칙, 제어를 학습하며 실습 예제를 통해 알아보았다. 다음 포스팅에서는 다른 문법 개념에 대해 작성해보려고 한다.

'코딩 공부 > 자바스크립트' 카테고리의 다른 글

17. 자바스크립트 모듈  (0) 2025.02.28
16. 자바스크립트 클래스  (1) 2025.02.27
14. 자바스크립트 클로저  (0) 2025.02.27
13. 자바스크립트 스코프  (0) 2025.02.27
12. 자바스크립트 호이스팅  (0) 2025.02.26
자바스크립트 클로저

자바스크립트 클로저

열세 번째 포스팅에서 스코프를 다루었다면, 이번에는 "문법 및 핵심 개념" 범주에 속하는 "클로저"를 탐구한다. 클로저(Closure)는 함수가 외부 스코프의 변수를 기억하고 접근할 수 있는 메커니즘으로, 데이터 캡슐화와 상태 관리에 활용된다.


클로저는 스코프와 밀접하게 연관되며, 자바스크립트의 강력한 기능을 제공한다. 이번 포스팅에서는 클로저의 개념, 동작 원리, 활용 방법, 그리고 실습 예제를 작성해볼 예정이다.


스코프와 함께 클로저는 자바스크립트의 고급 문법을 이해하는 데 필수적이다. 콘솔에서 예제를 실행하며 클로저의 동작을 체감할 수 있다.


클로저의 개념

클로저는 함수가 선언된 스코프의 변수를 함수 종료 후에도 기억하는 현상이다. 이는 함수와 스코프 체인이 결합된 결과이다. 다음은 기본적인 클로저 예제이다:

function outer() {
    var outerVar = '외부 변수';
    function inner() {
        console.log(outerVar);
    }
    return inner;
}
const innerFunc = outer();
innerFunc(); // "외부 변수"
        

위 예제는 내부 함수가 외부 변수에 접근한다.

클로저는 데이터의 비공개성과 상태 유지를 가능하게 한다. 이는 자바스크립트의 함수형 프로그래밍에서 핵심이다.


클로저의 동작 원리

클로저는 실행 컨텍스트와 스코프 체인에 의해 구현된다.


1. 스코프 체인

내부 함수는 외부 스코프를 참조한다:

function outer() {
    var x = 10;
    return function() {
        console.log(x);
    };
}
const closure = outer();
closure(); // 10
        

2. 메모리 유지

외부 함수가 종료되어도 변수는 유지된다:

function createCounter() {
    var count = 0;
    return function() {
        return ++count;
    };
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
        

예제: 클로저 메모리

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>클로저 메모리</title>
</head>
<body>
    <button id="btn">증가</button>
    <div id="count">0</div>
    <script>
        const btn = document.getElementById('btn');
        const countDiv = document.getElementById('count');
        const increment = (function() {
            var count = 0;
            return function() {
                return ++count;
            };
        })();

        btn.addEventListener('click', () => {
            countDiv.textContent = increment();
        });
    </script>
</body>
</html>
        

이 예제는 클로저로 카운터를 유지한다.


클로저 활용

클로저는 다양한 상황에서 활용된다.


1. 데이터 캡슐화

비공개 변수를 생성한다:

function createPerson(name) {
    var age = 0;
    return {
        getName: () => name,
        getAge: () => age,
        setAge: (newAge) => age = newAge
    };
}
const person = createPerson('홍길동');
console.log(person.getName()); // "홍길동"
console.log(person.getAge()); // 0
person.setAge(25);
console.log(person.getAge()); // 25
        

2. 함수 팩토리

동적인 함수를 생성한다:

function multiplier(factor) {
    return function(num) {
        return num * factor;
    };
}
const double = multiplier(2);
console.log(double(5)); // 10
        

예제: 클로저 팩토리

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>클로저 팩토리</title>
</head>
<body>
    <input type="number" id="input" value="5">
    <button id="doubleBtn">2배</button>
    <button id="tripleBtn">3배</button>
    <div id="result"></div>
    <script>
        function createMultiplier(factor) {
            return function(num) {
                return num * factor;
            };
        }
        const double = createMultiplier(2);
        const triple = createMultiplier(3);

        const input = document.getElementById('input');
        const doubleBtn = document.getElementById('doubleBtn');
        const tripleBtn = document.getElementById('tripleBtn');
        const result = document.getElementById('result');

        doubleBtn.addEventListener('click', () => {
            result.textContent = double(parseInt(input.value));
        });

        tripleBtn.addEventListener('click', () => {
            result.textContent = triple(parseInt(input.value));
        });
    </script>
</body>
</html>
        

이 예제는 클로저로 곱셈 함수를 생성한다.


실습 예제: 클로저 상태 관리

클로저를 활용한 상태 관리 예제이다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>클로저 상태</title>
    <style>
        #toggleBox {
            width: 100px;
            height: 100px;
            background: gray;
        }
    </style>
</head>
<body>
    <button id="toggleBtn">토글</button>
    <div id="toggleBox"></div>
    <script>
        const toggleBtn = document.getElementById('toggleBtn');
        const toggleBox = document.getElementById('toggleBox');
        const toggleState = (function() {
            var isOn = false;
            return function() {
                isOn = !isOn;
                toggleBox.style.backgroundColor = isOn ? 'red' : 'gray';
                return isOn;
            };
        })();

        toggleBtn.addEventListener('click', () => {
            toggleState();
        });
    </script>
</body>
</html>
        

이 예제는 클로저로 상태를 관리한다.

Closure Example

실무에서의 클로저

실무에서는 이벤트 핸들러에 활용한다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>클로저 이벤트</title>
</head>
<body>
    <button id="btn">클릭</button>
    <div id="log"></div>
    <script>
        const btn = document.getElementById('btn');
        const log = document.getElementById('log');
        btn.addEventListener('click', (function() {
            var clicks = 0;
            return function() {
                clicks++;
                log.textContent = `클릭 횟수: ${clicks}`;
            };
        })());
    </script>
</body>
</html>
        

이 예제는 클로저로 클릭 횟수를 기록한다.


주의할 점

클로저는 메모리를 유지하므로 누수가 발생할 수 있다. 불필요한 클로저는 정리한다. 복잡한 클로저는 가독성을 저하시킨다.


결론

클로저의 개념, 활용을 학습하며 실습 예제를 통해 이해한다. 다음 포스팅에서는 this 바인딩에 대해 작성해보려고 한다.

자바스크립트 스코프

자바스크립트 스코프

열두 번째 포스팅에서 호이스팅을 다루었다면, 이번에는 "문법 및 핵심 개념" 범주에 속하는 "스코프"에 대해 다루어본다. 스코프(Scope)는 변수의 접근 범위를 정의하며, 자바스크립트 코드의 실행과 변수 관리에 중요한 역할을 한다.


스코프는 변수의 생명 주기와 가시성을 제어한다. 이번 포스팅에서는 스코프의 개념, 전역 및 지역 스코프, 블록 스코프, 스코프 체인, 그리고 실습 예제를 상세히 다룬다.


호이스팅과 연계하여 스코프는 자바스크립트 엔진의 동작을 이해하는 데 필수적이다. 콘솔에서 예제를 실행하며 스코프의 동작을 체감할 수 있다.


스코프의 개념

스코프는 변수와 함수가 유효한 범위를 의미한다. 자바스크립트는 변수 선언 시 스코프를 생성하며, 이는 코드 실행 중 변수 접근 가능 여부를 결정한다. 다음은 기본적인 스코프 예제이다:

var globalVar = '전역';
function test() {
    var localVar = '지역';
    console.log(globalVar); // "전역"
    console.log(localVar); // "지역"
}
test();
console.log(localVar); // ReferenceError: localVar is not defined
        

위 예제는 전역 변수와 지역 변수의 스코프 차이를 보여준다.

스코프는 변수의 충돌을 방지하고, 코드의 안정성을 높인다. 이는 자바스크립트의 핵심 문법이다.


전역 스코프와 지역 스코프

스코프는 크게 전역 스코프와 지역 스코프로 나뉜다.


1. 전역 스코프

전역 스코프는 코드 최상위에서 선언된 변수가 속한다:

var global = '전역 변수';
console.log(global); // "전역 변수"
        

2. 지역 스코프

지역 스코프는 함수 내에서 선언된 변수가 속한다:

function localScope() {
    var local = '지역 변수';
    console.log(local); // "지역 변수"
}
localScope();
console.log(local); // ReferenceError: local is not defined
        

예제: 스코프 비교

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>스코프 비교</title>
</head>
<body>
    <script>
        var outer = '외부 변수';
        function innerFunc() {
            var inner = '내부 변수';
            console.log(outer); // "외부 변수"
            console.log(inner); // "내부 변수"
        }
        innerFunc();
        console.log(outer); // "외부 변수"
        try {
            console.log(inner);
        } catch (e) {
            console.log('에러:', e.message); // "inner is not defined"
        }
    </script>
</body>
</html>
        

이 예제는 전역과 지역 스코프를 확인한다.


블록 스코프

ES6에서 도입된 letconst는 블록 스코프를 지원한다.


1. var와 블록

var는 블록 스코프를 무시한다:

if (true) {
    var blockVar = '블록 변수';
}
console.log(blockVar); // "블록 변수"
        

2. let과 const

letconst는 블록 스코프를 따른다:

if (true) {
    let blockLet = '블록 let';
    const blockConst = '블록 const';
}
console.log(blockLet); // ReferenceError: blockLet is not defined
console.log(blockConst); // ReferenceError: blockConst is not defined
        

예제: 블록 스코프

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>블록 스코프</title>
</head>
<body>
    <script>
        for (var i = 0; i < 3; i++) {
            setTimeout(() => console.log(i), 100); // 3, 3, 3
        }
        for (let j = 0; j < 3; j++) {
            setTimeout(() => console.log(j), 100); // 0, 1, 2
        }
    </script>
</body>
</html>
        

이 예제는 varlet의 블록 스코프 차이를 보여준다.


스코프 체인

스코프 체인은 스코프가 중첩될 때 변수 접근 순서를 정의한다.


1. 중첩 스코프

내부 스코프는 외부 스코프에 접근 가능하다:

var outerVar = '외부';
function outerFunc() {
    var middleVar = '중간';
    function innerFunc() {
        var innerVar = '내부';
        console.log(outerVar); // "외부"
        console.log(middleVar); // "중간"
        console.log(innerVar); // "내부"
    }
    innerFunc();
}
outerFunc();
        

예제: 스코프 체인

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>스코프 체인</title>
</head>
<body>
    <script>
        const global = '전역';
        function level1() {
            const l1 = '레벨 1';
            function level2() {
                const l2 = '레벨 2';
                console.log(global); // "전역"
                console.log(l1); // "레벨 1"
                console.log(l2); // "레벨 2"
            }
            level2();
        }
        level1();
    </script>
</body>
</html>
        

이 예제는 스코프 체인을 확인한다.


실습 예제: 스코프 활용

스코프를 활용한 실습 예제이다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>스코프 실습</title>
</head>
<body>
    <button id="btn">실행</button>
    <div id="result"></div>
    <script>
        const btn = document.getElementById('btn');
        const result = document.getElementById('result');
        const globalVar = '전역 변수';

        btn.addEventListener('click', () => {
            result.textContent = '';
            function outer() {
                const outerVar = '외부 변수';
                function inner() {
                    const innerVar = '내부 변수';
                    result.textContent += `${globalVar}, ${outerVar}, ${innerVar}\n`;
                }
                inner();
            }
            outer();

            try {
                console.log(outerVar);
            } catch (e) {
                result.textContent += `에러: ${e.message}\n`; // "outerVar is not defined"
            }
        });
    </script>
</body>
</html>
        

이 예제는 스코프 체인과 오류를 확인한다.

Scope Example

실무에서의 스코프

실무에서는 스코프 충돌을 방지한다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>스코프 관리</title>
</head>
<body>
    <script>
        (function() {
            const moduleVar = '모듈 변수';
            console.log(moduleVar); // "모듈 변수"
        })();
        try {
            console.log(moduleVar);
        } catch (e) {
            console.log('에러:', e.message); // "moduleVar is not defined"
        }
    </script>
</body>
</html>
        

이 예제는 IIFE로 스코프를 격리한다.


주의할 점

전역 스코프 사용을 최소화한다. var 대신 letconst를 사용한다. 스코프 체인으로 인한 성능 저하를 고려한다.


결론

이 포스팅은 스코프의 개념, 체인을 학습하며 실습 예제를 통해 활용성을 확인한다. 다음 포스팅에서는 클로저를 다룬다.

자바스크립트 호이스팅

자바스크립트 호이스팅

열한 번째 포스팅까지 다양한 범주를 다루었다면, 이번에는 "문법 및 핵심 개념" 범주에 속하는 "호이스팅"에 대해 다루어보려고 한다. 호이스팅(Hoisting)은 자바스크립트에서 변수와 함수 선언이 코드 실행 전 스코프 최상단으로 끌어올려지는 동작을 의미한다.


호이스팅은 자바스크립트 엔진의 동작 방식과 관련 있으며, 코드 작성 시 예상치 못한 결과를 방지하려면 이해가 필수적이다. 이번 포스팅에서는 호이스팅의 개념, 변수와 함수의 호이스팅 차이, 동작 원리, 그리고 실습 예제를 상세히 다룬다. 약 20,000자의 분량으로 구성되며, 초보자도 실습을 통해 이해할 수 있도록 예제를 풍부하게 포함한다.


호이스팅은 자바스크립트의 핵심 문법을 이해하는 데 중요한 역할을 한다. 콘솔에서 예제를 실행하며 호이스팅의 동작을 체감할 수 있다.


호이스팅의 개념

호이스팅은 자바스크립트에서 선언문(변수, 함수)이 코드 실행 전 스코프의 최상단으로 이동하는 현상이다. 이는 변수나 함수를 선언하기 전에 사용할 수 있게 한다. 다음은 기본적인 호이스팅 예제이다:

console.log(x); // undefined
var x = 10;
        

위 예제는 변수 x가 선언되기 전에 접근해도 에러가 발생하지 않는다. 이는 var 선언이 호이스팅되어 코드 실행 전 스코프 상단으로 이동하기 때문이다.

호이스팅은 자바스크립트 엔진의 컴파일 단계에서 발생한다. 선언문은 메모리에 먼저 등록되며, 초기화는 코드 순서대로 진행된다. 이는 변수와 함수의 동작 방식에 영향을 미친다.


변수 호이스팅

변수의 호이스팅은 선언 방식에 따라 다르게 동작한다.


1. var 선언

var는 선언과 초기화가 호이스팅된다:

console.log(a); // undefined
var a = 5;
console.log(a); // 5
        

위 코드는 실행 시 var a;가 상단으로 이동하며, 초기화는 원래 위치에서 진행된다.


2. let과 const 선언

letconst는 선언만 호이스팅되며 초기화는 진행되지 않는다(일명 "일시적 사각지대", TDZ):

console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 10;

console.log(c); // ReferenceError: Cannot access 'c' before initialization
const c = 20;
        

예제: 변수 호이스팅 비교

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>변수 호이스팅</title>
</head>
<body>
    <script>
        console.log(varTest); // undefined
        var varTest = 'var 테스트';

        try {
            console.log(letTest);
        } catch (e) {
            console.log('let 에러:', e.message); // "Cannot access 'letTest' before initialization"
        }
        let letTest = 'let 테스트';
    </script>
</body>
</html>
        

이 예제는 varlet의 호이스팅 차이를 확인한다.


함수 호이스팅

함수의 호이스팅은 선언 방식에 따라 다르다.


1. 함수 선언문

함수 선언문은 전체가 호이스팅된다:

sayHello(); // "안녕하세요"
function sayHello() {
    console.log('안녕하세요');
}
        

2. 함수 표현식

함수 표현식은 변수 호이스팅 규칙을 따른다:

sayHi(); // TypeError: sayHi is not a function
var sayHi = function() {
    console.log('안녕');
};
        

예제: 함수 호이스팅 비교

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>함수 호이스팅</title>
</head>
<body>
    <script>
        funcDecl(); // "선언문 호출"
        function funcDecl() {
            console.log('선언문 호출');
        }

        try {
            funcExpr();
        } catch (e) {
            console.log('표현식 에러:', e.message); // "funcExpr is not a function"
        }
        var funcExpr = function() {
            console.log('표현식 호출');
        };
    </script>
</body>
</html>
        

이 예제는 함수 선언문과 표현식의 차이를 보여준다.


호이스팅의 동작 원리

호이스팅은 자바스크립트 엔진의 실행 컨텍스트에서 발생한다.


1. 컴파일 단계

선언문은 스코프 상단으로 이동한다:

// 원본
console.log(x);
var x = 10;

// 컴파일 후
var x;
console.log(x);
x = 10;
        

2. 실행 단계

초기화와 할당은 코드 순서대로 진행한다:

console.log(y); // undefined
var y;
y = 20;
        

예제: 실행 컨텍스트

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>실행 컨텍스트</title>
</head>
<body>
    <script>
        function test() {
            console.log(a); // undefined
            var a = 100;
            console.log(a); // 100
        }
        test();
    </script>
</body>
</html>
        

이 예제는 함수 스코프 내 호이스팅을 확인한다.


실습 예제: 호이스팅 이해

호이스팅을 활용한 실습 예제이다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>호이스팅 실습</title>
</head>
<body>
    <button id="btn">실행</button>
    <div id="result"></div>
    <script>
        const btn = document.getElementById('btn');
        const result = document.getElementById('result');

        btn.addEventListener('click', () => {
            result.textContent = '';
            logBefore(); // "선언 전 호출 가능"
            function logBefore() {
                result.textContent += '선언 전 호출 가능\n';
            }

            try {
                logAfter();
            } catch (e) {
                result.textContent += `에러: ${e.message}\n`; // "logAfter is not a function"
            }
            var logAfter = function() {
                result.textContent += '선언 후 호출\n';
            };
        });
    </script>
</body>
</html>
        

이 예제는 함수 선언문과 표현식의 호이스팅 차이를 확인한다.

Hoisting Example

실무에서의 호이스팅

실무에서는 호이스팅으로 인한 오류를 방지한다:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>호이스팅 방지</title>
</head>
<body>
    <script>
        function safeCode() {
            'use strict';
            console.log(x); // ReferenceError: x is not defined
            var x = 10;
        }
        safeCode();
    </script>
</body>
</html>
        

이 예제는 'use strict'로 호이스팅 오류를 방지한다.


주의할 점

호이스팅은 변수 초기화를 보장하지 않는다. letconst를 사용하여 TDZ를 활용한다. 함수 표현식을 선호한다.


결론

호이스팅의 개념, 동작 원리를 학습하며 실습 예제를 통해 이해한다. 다음 포스팅에서는 스코프를 다룰 예정이다.

+ Recent posts