1. JavaScript란?
JavaScript는 오늘날 웹 브라우저뿐만 아니라 서버(Node.js), 모바일 앱(React Native), 데스크탑 앱(Electron) 등 거의 모든 환경에서 동작하는 가장 인기 있는 프로그래밍 언어입니다.
2. 실행 환경 구축 (Node.js & VS Code)
JavaScript는 원래 웹 브라우저 안에서만 실행되도록 고안되었으나, Node.js의 등장으로 브라우저 밖(서버, 로컬 터미널 등)에서도 단독으로 실행할 수 있게 되었습니다. 로컬 개발 환경을 OS별로 세팅해 보겠습니다.
2.1 운영체제별 Node.js 설치
🪟 Windows 설치
- Node.js 공식 홈페이지 설치: Node.js 공식 홈페이지에 접속하여 안정적이고 검증된 LTS(Long Term Support) 인스톨러(
.msi)를 다운로드해 실행하고 기본값으로 설치합니다. - 설치 확인: cmd 또는 PowerShell 창을 열고 아래 명령어로 버전 번호가 올바르게 호출되는지 확인합니다.
node -v npm -vbash
🍎 macOS 설치
- Homebrew 설치 방식 (추천): macOS 터미널에서 패키지 관리자를 통해 원클릭 설치가 가능합니다.
brew install nodebash - 공식 패키지 설치 방식: Node.js 공식 홈페이지에서 macOS 인스톨러(
.pkg)를 다운로드하여 마법사를 통해 설치합니다. - 설치가 끝나면 터미널에서
node -v와 패키지 빌드 툴인npm -v를 실행하여 확인합니다.
🐧 Linux (Ubuntu) 설치
리눅스 환경에서는 패키지 매니저를 이용해 최신 LTS 버전을 간단히 설치할 수 있습니다.
sudo apt update
sudo apt install nodejs npm
# 설치 버전 검증
node -vbash
2.2 VS Code에서 JavaScript 실행 및 확장 도구
- Prettier & ESLint 설치: VS Code 확장 마켓플레이스(
Ctrl + Shift + X)에서 코드 포맷팅을 위한 Prettier와 문법 및 코드 규격을 잡아주는 ESLint를 설치합니다. - 로컬 터미널 실행 (Node.js 활용):
프로젝트 폴더에
index.js파일을 만들고 아래 코드를 입력합니다.const message = "로컬 Node.js 환경에서 자바스크립트 실행 완료!"; console.log(message);javascriptVS Code의 통합 터미널(
Ctrl + `)에서 아래 명령어를 수행하면 로컬에서 즉시 실행이 완료됩니다.node index.jsbash
3. 변수 (Variables)
JavaScript에서 값을 저장하기 위해 사용하는 변수는 선언 키워드인 const와 let을 통해 정의합니다. 과거에 사용되던 var는 함수 레벨 스코프와 호이스팅 문제로 인해 현대 개발에서는 사용을 전면 배제합니다.
// 1. const (재할당 불가, 기본적으로 사용 권장)
const name = 'JavaScript';
// name = 'ES6'; // TypeError: Assignment to constant variable.
// 2. let (재할당 가능)
let count = 0;
count = 1; // 정상 동작javascript
4. 자료형 & 메모리 기초 (Data Types & Memory)
JavaScript는 동적 타입 언어로, 변수 선언 시 타입을 명시하지 않고 값이 대입될 때 타입이 결정됩니다. 자료형은 원시 타입(Primitive Types)과 객체 타입(Object Types)으로 나뉩니다.
// 원시 타입 (Primitive Types)
const numberVal = 42; // 숫자형 (정수, 실수 모두 Number)
const stringVal = "안녕하세요"; // 문자열
const booleanVal = true; // 논리형 (true, false)
const nullVal = null; // 값이 없음 (개발자가 명시적으로 비움)
let undefinedVal; // 선언만 되고 값이 할당되지 않음 (자동 부여)
// 객체 타입 (Object Types)
const objectVal = { name: "철수", age: 20 };
const arrayVal = [1, 2, 3];javascript
5. 연산자와 제어문 (Operators & Control Flow)
조건에 따라 흐름을 제어하는 조건문과 반복문은 프로그래밍의 핵심 제어 흐름을 구성합니다.
// 1. 일치 연산자 (===, !==) - 타입과 값을 모두 비교하므로 추천
if (1 === '1') {
console.log("같다"); // 실행 안 됨
}
// 2. 조건문 (if-else)
const score = 85;
if (score >= 90) {
console.log('A 학점');
} else if (score >= 80) {
console.log('B 학점');
} else {
console.log('F 학점');
}
// 3. 반복문 (for-of)
const colors = ['red', 'green', 'blue'];
for (const color of colors) {
console.log(color); // 원소들을 하나씩 순회하며 출력
}javascript
6. 실행 컨텍스트와 클로저 (Execution Context & Closures) (중급)
JavaScript는 렉시컬 스코프(Lexical Scope)를 따릅니다. **클로저(Closure)**는 함수가 선언된 환경의 변수들을 기억하여, 외부 함수 호출이 끝난 뒤에도 내부 함수가 그 외부 변수에 계속해서 액세스할 수 있는 중급 핵심 동작 원리입니다.
function createCounter() {
let count = 0; // 외부 함수 안의 비공개 변수 (상태 은닉)
return {
increment() {
count++;
return count;
},
decrement() {
count--;
return count;
}
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
// count 변수는 직접 외부에서 수정할 수 없으며 오직 클로저 메서드를 통해서만 수정 및 안전히 보호됨javascript
7. 함수 (Functions)
JavaScript 함수는 일급 객체로, 변수에 할당하거나 다른 함수의 인자로 전달하고 반환할 수 있어 매우 유연합니다. 전통적인 함수 선언문 외에도 화살표 함수(Arrow Function)를 널리 사용합니다.
// 1. 일반 함수 선언문
function add(a, b) {
return a + b;
}
// 2. 화살표 함수 (Arrow Function)
const multiply = (a, b) => a * b;
console.log(add(3, 4)); // 7
console.log(multiply(3, 4)); // 12javascript
8. 배열 (Arrays)
JavaScript 배열은 동적으로 크기가 변하며, 풍부하고 강력한 내장 메서드들을 지원하여 데이터를 가공하기 매우 유용합니다.
const nums = [3, 1, 4, 1, 5, 9, 2, 6];
// ── 추가 / 제거 ──────────────────────────────
nums.push(7); // 끝에 추가 → [..., 7]
nums.pop(); // 끝에서 제거
nums.unshift(0); // 앞에 추가 → [0, ...]
nums.shift(); // 앞에서 제거
nums.splice(2, 1); // 인덱스 2에서 1개 제거
const sliced = nums.slice(1, 4); // 인덱스 1~3 새 배열로 복사
// ── 탐색 ──────────────────────────────────────
const idx = nums.indexOf(5); // 첫 번째 위치 (-1: 없음)
const found = nums.find(n => n > 4); // 조건 맞는 첫 값
const fIdx = nums.findIndex(n => n > 4); // 조건 맞는 첫 인덱스
const hasNine = nums.includes(9); // true/false
const allPos = nums.every(n => n > 0); // 모두 양수?
const someGt5 = nums.some(n => n > 5); // 하나라도 5 초과?javascript
고차 함수 메서드 (map / filter / reduce)
배열 데이터를 변환·필터링·축약하는 함수형 패턴의 핵심입니다. 체이닝으로 결합해서 사용합니다.
const products = [
{ name: '키보드', price: 45000, inStock: true },
{ name: '마우스', price: 25000, inStock: false },
{ name: '모니터', price: 320000, inStock: true },
];
// map: 각 요소를 새 값으로 변환
const names = products.map(p => p.name);
// ['키보드', '마우스', '모니터']
// filter: 조건에 맞는 요소만 추출
const available = products.filter(p => p.inStock);
// [{name:'키보드',...}, {name:'모니터',...}]
// reduce: 배열을 단일 값으로 축약
const total = products.reduce((acc, p) => acc + p.price, 0);
// 390000
// 체이닝: 재고 있는 상품의 가격 합계
const stockTotal = products
.filter(p => p.inStock)
.reduce((acc, p) => acc + p.price, 0);
// 365000javascript
정렬 / 평탄화 / 기타 유용 메서드
// sort: 원본 배열을 정렬 (비교 함수 필수!)
const scores = [40, 100, 1, 5, 25];
scores.sort((a, b) => a - b); // 오름차순: [1, 5, 25, 40, 100]
scores.sort((a, b) => b - a); // 내림차순: [100, 40, 25, 5, 1]
// flat: 중첩 배열 평탄화
const nested = [1, [2, 3], [4, [5, 6]]];
nested.flat(); // [1, 2, 3, 4, [5, 6]]
nested.flat(2); // [1, 2, 3, 4, 5, 6]
// flatMap: map + flat(1) 결합
const sentences = ['hello world', 'foo bar'];
sentences.flatMap(s => s.split(' ')); // ['hello','world','foo','bar']
// 스프레드로 배열 복사·병합
const a = [1, 2];
const b = [3, 4];
const merged = [...a, ...b]; // [1, 2, 3, 4]
const copy = [...a]; // 얕은 복사javascript
9. 객체 (Objects)
객체는 키(Key)와 값(Value)의 쌍으로 구성된 프로퍼티의 집합입니다. 복잡한 구조의 데이터 표현과 상태 관리에 핵심이 됩니다.
const user = {
name: '김철수',
age: 25,
address: { city: '서울', zip: '04524' }, // 중첩 객체
greet() {
console.log(`안녕하세요, ${this.name}입니다.`);
}
};
// 프로퍼티 접근
console.log(user.name); // '김철수'
console.log(user['age']); // 25 (동적 키 접근)
user.greet();javascript
구조 분해 할당 (Destructuring)
// 객체 구조 분해 + 기본값 + 별칭
const { name, age = 0, address: { city } } = user;
console.log(name, city); // '김철수' '서울'
// 함수 파라미터에서 구조 분해 (가장 많이 쓰는 패턴)
function showUser({ name, age }) {
console.log(`${name} (${age}세)`);
}
showUser(user);javascript
옵셔널 체이닝 (?.) · 널 병합 연산자 (??)
const data = { user: null };
// ?. : 중간에 null/undefined면 undefined 반환 (에러 없음)
console.log(data.user?.name); // undefined
console.log(data.user?.address?.zip); // undefined
// ?? : 좌항이 null/undefined 일 때만 우항 반환
const port = data.config?.port ?? 3000; // 3000
const name2 = '' ?? '기본값'; // '' (falsy여도 ?? 는 넘어감)javascript
객체 순회 · 복사 · 병합
const obj = { a: 1, b: 2, c: 3 };
// 순회
Object.keys(obj); // ['a','b','c']
Object.values(obj); // [1, 2, 3]
Object.entries(obj); // [['a',1],['b',2],['c',3]]
for (const [key, val] of Object.entries(obj)) {
console.log(`${key}: ${val}`);
}
// 얕은 복사 & 병합 (스프레드)
const copy = { ...obj }; // { a:1, b:2, c:3 }
const merged = { ...obj, d: 4, b: 99 }; // b 덮어쓰기: { a:1,b:99,c:3,d:4 }
// Object.assign (동일 결과)
const merged2 = Object.assign({}, obj, { d: 4 });javascript
10. 프로토타입 체인과 클래스 상속 심화 (Prototypes & Classes) (중급)
JavaScript는 프로토타입 기반의 상속 언어입니다. 모든 객체는 숨겨진 링크인 [[Prototype]](__proto__)을 가지고 부모 객체를 가리키며, ES6 class는 이 프로토타입 메커니즘을 보다 명확하고 깔끔하게 추상화한 것에 불과합니다.
class Employee {
constructor(name, salary) {
this.name = name;
this.salary = salary;
}
getDetails() {
return `${this.name}의 연봉은 ${this.salary}원입니다.`;
}
}
// 상속 및 super 키워드 활용
class Manager extends Employee {
constructor(name, salary, department) {
super(name, salary); // 부모 클래스의 생성자 호출
this.department = department;
}
// 메서드 오버라이딩 및 부모 메서드 체이닝
getDetails() {
return `${super.getDetails()} 부서: ${this.department}`;
}
}
const mgr = new Manager("이영희", 70000000, "개발본부");
console.log(mgr.getDetails());javascript
11. 비동기 처리와 이벤트 루프 (Asynchronous & Event Loop) (중급)
JavaScript는 싱글 스레드로 작동하지만 **이벤트 루프(Event Loop)**를 통해 강력한 비동기 논블로킹(Non-blocking) I/O 작업을 완수합니다. 특히 복수 비동기 작업을 병렬 처리하는 Promise.all 기법은 실무 백엔드/프런트 통신의 정석입니다.
// 1. 다중 비동기 API 요청 병렬 즉시 처리 (Promise.all)
async function fetchAllData() {
try {
const [userResp, configResp] = await Promise.all([
fetch('https://api.example.com/users'),
fetch('https://api.example.com/config')
]);
const users = await userResp.json();
const config = await configResp.json();
console.log("전체 로드 완료:", users, config);
} catch (err) {
console.error("비동기 처리 실패:", err);
}
}javascript
Promise의 콜백(
.then 또는 await 복귀 점)은 일반 setTimeout 같은 매크로태스크보다 **우선적으로 처리되는 마이크로태스크 큐**에 들어갑니다. 이는 비동기 코드 실행 타이밍 버그를 방지하는 중급 웹 개발의 핵심 기초 상식입니다.
12. DOM 조작 (DOM Manipulation)
브라우저 환경의 JavaScript는 문서 객체 모델(DOM) API를 통해 HTML 요소의 구조, 스타일, 내용 등을 동적으로 바꿀 수 있습니다.
// ── 요소 선택 ─────────────────────────────────
const title = document.querySelector('.main-title'); // CSS 선택자 (첫 번째)
const items = document.querySelectorAll('.item'); // NodeList (전체)
const byId = document.getElementById('header');
// ── 내용 · 속성 변경 ────────────────────────────
title.textContent = '반갑습니다!'; // HTML 태그 없이 텍스트만
title.innerHTML = '반갑습니다!'; // HTML 파싱 포함
title.setAttribute('data-lang', 'ko');
title.style.color = 'var(--blue)';
title.style.fontWeight = 'bold';javascript
요소 생성 · 추가 · 삭제
// 요소 생성 및 삽입
const li = document.createElement('li');
li.textContent = '새 항목';
li.classList.add('item', 'active');
const ul = document.querySelector('ul');
ul.appendChild(li); // 끝에 추가
ul.prepend(li); // 앞에 추가
ul.insertBefore(li, ul.firstChild); // 특정 위치에 삽입
// innerHTML로 일괄 생성 (XSS 주의 — 사용자 입력은 금지)
ul.innerHTML = items.map(i => `<li>${i}</li>`).join('');
// 요소 삭제
li.remove(); // 자기 자신 삭제
ul.removeChild(ul.lastChild); // 부모에서 자식 삭제javascript
classList · dataset
const card = document.querySelector('.card');
// classList API
card.classList.add('highlight');
card.classList.remove('hidden');
card.classList.toggle('active'); // 있으면 제거, 없으면 추가
card.classList.contains('active'); // true/false
// data-* 속성 (HTML: data-user-id="42")
card.dataset.userId = '42';
card.dataset.loading = 'true';
console.log(card.dataset.userId); // '42'javascript
13. 이벤트 (Events)
이벤트 리스너를 요소에 등록하여 사용자의 클릭, 키보드 입력, 마우스 이동 등 다양한 행동(이벤트)을 감지하고 반응 코드를 작동시킵니다.
const btn = document.querySelector('#submitBtn');
// 기본 이벤트 등록 / 제거
function handleClick(e) {
e.preventDefault(); // 기본 동작 차단 (예: 폼 제출, 링크 이동)
e.stopPropagation(); // 이벤트 버블링 중단
console.log('클릭됨', e.target);
}
btn.addEventListener('click', handleClick);
btn.removeEventListener('click', handleClick); // 정확히 같은 참조 필요javascript
이벤트 버블링 & 위임 (Event Delegation)
이벤트는 발생한 요소에서 시작해 부모로 전파(버블링)됩니다. 이를 활용해 부모 하나에 리스너를 달아 다수의 자식을 처리하는 이벤트 위임이 성능에 유리합니다.
// ❌ 비효율: 각 버튼마다 리스너 100개
document.querySelectorAll('.btn').forEach(b => b.addEventListener('click', handler));
// ✅ 효율적: 부모에 리스너 1개 (이벤트 위임)
document.querySelector('#btn-group').addEventListener('click', (e) => {
const btn = e.target.closest('.btn'); // 클릭된 .btn 탐색
if (!btn) return;
const action = btn.dataset.action; // data-action 속성 읽기
console.log('action:', action);
});javascript
자주 쓰는 이벤트 종류
// 마우스
el.addEventListener('click', handler); // 클릭
el.addEventListener('dblclick', handler); // 더블클릭
el.addEventListener('mouseover', handler); // 마우스 진입
el.addEventListener('mouseout', handler); // 마우스 이탈
// 키보드
document.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && e.ctrlKey) console.log('Ctrl+Enter');
});
// 폼
form.addEventListener('submit', (e) => { e.preventDefault(); /* 제출 처리 */ });
input.addEventListener('input', (e) => console.log(e.target.value)); // 실시간 입력
input.addEventListener('change', handler); // 값 변경 후 포커스 잃을 때
input.addEventListener('focus', handler); // 포커스 획득
input.addEventListener('blur', handler); // 포커스 잃음
// 문서 / 윈도우
window.addEventListener('resize', handler);
window.addEventListener('scroll', handler);
document.addEventListener('DOMContentLoaded', handler); // DOM 파싱 완료 시javascript
14. ES6+ 주요 기능 (Modern JS Features)
현대 JavaScript 개발을 우아하고 심플하게 만들어주는 최신 주요 구문 문법들입니다.
모듈 시스템 (ES Modules)
// math.js — 내보내기
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export default class Calculator { /* ... */ }
// main.js — 가져오기
import Calculator, { PI, add } from './math.js';
import * as MathUtils from './math.js'; // 전체 네임스페이스
// 동적 import (코드 스플리팅)
const { add: addFn } = await import('./math.js');javascript
Symbol · WeakMap · WeakSet
// Symbol: 유일하고 불변한 식별자
const ID = Symbol('id');
const obj = { [ID]: 42, name: 'test' };
console.log(obj[ID]); // 42
console.log(Object.keys(obj)); // ['name'] — Symbol은 열거되지 않음
// WeakMap: 키가 GC 대상이 되면 자동 제거 (메모리 누수 방지)
const cache = new WeakMap();
function process(element) {
if (cache.has(element)) return cache.get(element);
const result = heavyComputation(element);
cache.set(element, result);
return result;
}javascript
Nullish Coalescing · Optional Chaining (실전 핵심)
const user = { profile: null };
// ?. : null/undefined 체인에서 안전하게 접근
const city = user.profile?.address?.city; // undefined (에러 없음)
const fn = obj.method?.(); // 메서드도 안전하게 호출
// ?? : null/undefined일 때만 기본값 (0이나 ''는 통과)
const count = user.count ?? 0; // count가 0이면 0 유지 (|| 와 다름!)
const name = user.name ?? '익명';
// ??= 할당 연산자 (null/undefined일 때만 할당)
user.role ??= 'guest';javascript
제너레이터 (Generator)
function* range(start, end, step = 1) {
for (let i = start; i < end; i += step) {
yield i;
}
}
// 이터러블로 사용
for (const n of range(0, 10, 2)) {
console.log(n); // 0, 2, 4, 6, 8
}
// 무한 시퀀스
function* idGenerator() {
let id = 1;
while (true) yield id++;
}
const gen = idGenerator();
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2javascript
최신 문법 정리 (ES2020~ES2024)
// Promise.allSettled: 성공/실패 무관 모든 결과 수집
const results = await Promise.allSettled([
fetch('/api/a'),
fetch('/api/b'),
]);
results.forEach(r => {
if (r.status === 'fulfilled') console.log(r.value);
else console.error(r.reason);
});
// Object.groupBy (ES2024)
const items = [{type:'a',val:1},{type:'b',val:2},{type:'a',val:3}];
const grouped = Object.groupBy(items, i => i.type);
// { a: [{...},{...}], b: [{...}] }
// Array.at() — 음수 인덱스 지원
[1,2,3].at(-1); // 3 (마지막 요소)
// structuredClone — 깊은 복사
const deep = structuredClone({ a: { b: 1 } });javascript
15. 추천 학습 경로 & 다음 단계 (Recommended Path & Next Steps)
JavaScript의 기초와 중급 작동 원리(클로저, 이벤트루프)를 완전히 익히셨다면, 아래의 학습 로드맵을 밟아 초일류 프런트엔드 빌더로 성장을 가속하세요!
1. JavaScript 변수/함수 기초 → 2. 클로저 및 실행 컨텍스트 파헤치기 → 3. 이벤트 루프 및 마이크로태스크 큐 비동기 타이밍 정복 → 4. TypeScript 정적 타입 선언으로 결합 설계 도약
연계 가이드: React 가이드 · Vue 가이드 · TypeScript 가이드 · 🟢 Node.js 가이드 · ▲ Next.js 가이드