1. 제어 흐름 (Flow Control)
제어 흐름이란 코드의 실행 순서를 개발자가 의도적으로 제어하는 것이다. 이를 통해 프로그램은 특정 조건에 따라 다른 코드를 실행하거나, 특정 코드를 반복적으로 실행할 수 있다.
표현식과 문 (Expression vs. Statement)
표현식 (Expression): 값으로 평가될 수 있는 모든 식이다. 표현식은 하나의 값으로 귀결되므로, 변수에 할당되거나 다른 표현식의 일부가 될 수 있다.
5 // 리터럴 표현식 x + 10 // 연산자 표현식 myFunction() // 함수 호출 표현식 const name = "Park"; // 할당 자체도 하나의 표현식이다.문 (Statement): 프로그램을 구성하는 기본 단위이자, 컴퓨터에 내리는 명령이다. 문은 값으로 평가되지 않을 수도 있다. 조건문, 반복문, 변수 선언 등이 모두 문에 해당한다.
let x = 5; // 변수 선언문 if (x > 0) { ... } // 조건문 for (let i=0; i<5; i++) { ... } // 반복문이 둘을 구분하는 것은 제어 흐름을 이해하는 기초가 된다. 조건문이나 반복문은 특정 조건(표현식)의 평가 결과에 따라 실행할 문을 결정하는 구조이기 때문이다.
조건문 (Conditional Statements)
주어진 조건식의 평가 결과(truthy 또는 falsy)에 따라 실행할 코드 블록을 결정한다.
if...else if...else문: 가장 일반적인 조건문이다.const score = 85; if (score >= 90) { console.log("A 등급입니다."); } else if (score >= 80) { console.log("B 등급입니다."); // 이 블록이 실행된다. } else { console.log("C 등급 이하입니다."); }
반복문 (Loops)
특정 조건을 만족하는 동안 코드 블록을 반복적으로 실행한다.
for루프: 반복 횟수가 명확하거나, 특정 규칙에 따라 변하는 카운터가 필요할 때 주로 사용된다.// 0부터 4까지 5번 반복 for (let i = 0; i < 5; i++) { console.log(`현재 i의 값: ${i}`); }while루프 (조건부 루프): 반복 횟수가 불명확하고, 특정 조건이 만족될 때까지 계속 반복해야 할 때 사용된다. 조건식이 먼저 평가되므로, 조건이 처음부터 거짓이면 한 번도 실행되지 않을 수 있다.let isConnected = false; let attempts = 0; while (!isConnected && attempts < 3) { console.log("연결 시도 중..."); attempts++; if (Math.random() > 0.5) { // 50% 확률로 연결 성공 가정 isConnected = true; } } console.log(isConnected ? "연결 성공!" : "연결 실패.");
break와 continue
반복문 내부에서 실행 흐름을 제어하기 위해 사용된다.
break: 현재 실행 중인 반복문을 즉시 종료하고, 반복문 다음 코드로 실행 흐름을 이동시킨다.// 배열에서 첫 번째 짝수를 찾으면 즉시 종료 const numbers = [1, 3, 5, 6, 7, 9]; for (let num of numbers) { if (num % 2 === 0) { console.log(`첫 번째 짝수 ${num}을(를) 찾았습니다.`); break; // 반복문을 완전히 빠져나온다. } }continue: 현재 반복 주기를 건너뛰고, 반복문의 다음 주기를 즉시 시작한다.// 1부터 10까지의 숫자 중 홀수만 출력 for (let i = 1; i <= 10; i++) { if (i % 2 === 0) { // i가 짝수이면 continue; // 현재 반복을 건너뛰고 다음 i로 넘어간다. } console.log(i); }
2. 예외 처리 (Exception Handling)
프로그램 실행 중 발생하는 예기치 않은 문제(에러)에 대처하고, 프로그램이 비정상적으로 종료되는 것을 방지하는 메커니즘이다.
예외 상황의 종류
자바스크립트에는 다양한 내장 에러 객체가 있다.
SyntaxError: 문법 규칙에 맞지 않는 코드를 실행하려 할 때 발생.ReferenceError: 존재하지 않는 변수나 함수를 참조할 때 발생.TypeError: 값이 예상된 타입이 아닐 때 발생 (예:null의 속성에 접근).
throw와 Error 객체
개발자가 의도적으로 에러를 발생시켜야 할 때 throw 문을 사용한다. 이때, 에러에 대한 상세 정보(메시지, 스택 추적 등)를 담고 있는 Error 객체를 생성하여 던지는 것이 일반적이다.
function divide(a, b) {
if (b === 0) {
// 의도적으로 에러를 발생시킨다.
throw new Error("0으로 나눌 수 없습니다.");
}
return a / b;
}
try...catch 문
에러가 발생할 가능성이 있는 코드를 안전하게 실행하고, 에러 발생 시 대처하기 위해 사용된다.
try블록: 에러가 발생할 수 있는 코드를 이 블록 안에 작성한다.catch블록:try블록에서 에러가 발생하면, 실행이 즉시 중단되고catch블록으로 제어가 넘어온다. 발생한 에러 객체는catch블록의 매개변수로 전달된다.finally블록 (선택 사항): 에러 발생 여부와 관계없이 항상 실행되는 코드 블록이다. 주로 파일 닫기, 네트워크 연결 종료 등 반드시 실행되어야 하는 정리 코드를 작성할 때 사용된다.
try {
console.log("나누기 연산을 시작합니다.");
const result = divide(10, 0); // 여기서 에러가 발생!
console.log(`결과: ${result}`); // 이 줄은 실행되지 않는다.
} catch (error) {
// throw된 Error 객체를 받는다.
console.error(`[에러 발생] ${error.message}`);
} finally {
console.log("나누기 연산이 종료되었습니다."); // 이 코드는 항상 실행된다.
}
3. 객체 (Object)
객체란?
자바스크립트에서 객체는 여러 값(원시 값 또는 다른 객체)의 컬렉션을 키(key)와 값(value)의 쌍으로 저장하는 복합 데이터 구조이다. 키는 문자열 또는 심볼이며, 값은 모든 데이터 타입을 가질 수 있다. 객체 내의 함수는 특별히 메소드(Method)라고 부른다.
const user = {
name: "Park", // 'name'은 키, "Park"은 값 (속성, Property)
age: 30,
isAdmin: true,
greet: function() { // greet은 메소드
console.log(`Hello, my name is ${this.name}.`);
}
};
객체 속성 제어
- 접근:
user.name(점 표기법) 또는user['name'](괄호 표기법) - 추가/수정:
user.location = 'Seoul';또는user.age = 31; - 삭제:
delete user.isAdmin;
객체 간 비교와 복사
비교: 객체를 비교 연산자(
===)로 비교하면 값의 동등성이 아닌 참조(메모리 주소)의 동일성을 비교한다. 따라서 내용이 같더라도 별개로 생성된 두 객체는 항상false이다.const obj1 = { a: 1 }; const obj2 = { a: 1 }; console.log(obj1 === obj2); // false복사:
얕은 복사 (Shallow Copy): 객체의 최상위 속성들만 복사한다. 속성의 값이 원시 값이면 값이 복사되지만, 객체이면 참조(주소)가 복사된다.
const original = { a: 1, b: { c: 2 } }; const copied = { ...original }; // Spread 문법 또는 Object.assign 사용 copied.a = 100; // 원본에 영향 없음 copied.b.c = 200; // 원본에도 영향 있음! (b 객체의 주소를 공유하므로) console.log(original.b.c); // 200깊은 복사 (Deep Copy): 객체 내부의 모든 객체까지 재귀적으로 복사하여 완전히 새로운 객체를 만든다.
JSON.parse(JSON.stringify(obj))가 간편한 방법이지만, 함수나undefined등을 유실하는 단점이 있어 완벽하지 않다. 실무에서는 Lodash 라이브러리의_.cloneDeep()등을 사용하기도 한다.
객체의 종류
자바스크립트의 객체는 크게 세 가지로 나눌 수 있다.
- 표준 내장 객체 (Standard Built-in Objects):
Object,String,Number,Boolean,Symbol,Array,Date,Math,RegExp등 ECMAScript 사양에 정의된 객체들이다. - 호스트 객체 (Host Objects): 자바스크립트 실행 환경(브라우저, Node.js)에서 제공하는 객체들이다. (예:
window,document,location등) - 사용자 정의 객체 (User-defined Objects): 개발자가 직접 생성한 객체이다.
4. 주요 내장 객체
Number, Math
Number: 숫자 원시 값을 다루는 래퍼(wrapper) 객체이다.Number.parseInt(),Number.isNaN()등 유용한 정적 메소드를 제공한다.Math: 수학적인 상수와 함수를 위한 속성과 메소드를 가진 정적(static) 객체이다. 인스턴스를 생성할 수 없다.Math.PI; // 3.14159... (원주율) Math.random(); // 0과 1 사이의 난수 생성 Math.floor(4.9); // 4 (내림) Math.ceil(4.1); // 5 (올림) Math.max(1, 10, -5); // 10 (최댓값)
Date
날짜와 시간을 다루는 객체이다.
const now = new Date(); // 현재 날짜와 시간
console.log(now.getFullYear()); // 년도
console.log(now.getMonth() + 1); // 월 (0부터 시작하므로 +1 필요)
console.log(now.toLocaleString()); // 사용자의 문화권에 맞는 문자열로 변환
String
문자열 원시 값을 다루는 래퍼 객체이며, 다양한 텍스트 처리 메소드를 제공한다.
const str = " Hello, World! ";
str.length; // 15
str.trim(); // "Hello, World!" (양 끝 공백 제거)
str.toUpperCase(); // " HELLO, WORLD! " (대문자 변환)
str.substring(1, 6); // "Hello" (인덱스 1부터 5까지)
str.split(','); // [" Hello", " World! "] (',' 기준으로 분리하여 배열 생성)
정규 표현식 (RegExp)
문자열에서 특정 패턴을 검색, 대체, 추출하기 위한 패턴이다. 복잡한 문자열 처리를 간결하게 표현할 수 있다.
- 리터럴 방식:
/pattern/flags - 생성자 방식:
new RegExp('pattern', 'flags')
const email = "test@example.com";
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
// test(): 패턴에 부합하는지 여부를 boolean으로 반환
if (emailRegex.test(email)) {
console.log("유효한 이메일 형식입니다.");
}
const url = "Visit https://www.example.com";
const httpRegex = /https?:\/\/[^\s]+/g;
// match(): 패턴에 부합하는 모든 부분을 배열로 반환
const foundUrls = url.match(httpRegex);
console.log(`찾은 URL: ${foundUrls}`); // "https://www.example.com"
5. 컬렉션 (Collections)
컬렉션은 여러 개의 값을 하나의 단위로 묶어 효율적으로 관리하기 위한 자료구조이다. ES6부터는 Array 외에도 Map, Set, WeakMap, WeakSet과 같은 다양한 목적의 컬렉션이 표준으로 도입되었다.
인덱스 기반 컬렉션 (Indexed Collection) - Array
배열은 순서가 있는 값의 목록을 저장하는 가장 기본적인 컬렉션이다. 각 값은 인덱스(index)를 통해 접근할 수 있으며, 인덱스는 0부터 시작하는 정수이다.
const fruits = ["사과", "바나나", "체리"];
console.log(fruits[1]); // "바나나"
키 기반 컬렉션 (Keyed Collections) - Map, WeakMap
Map:- 개념:
Object와 유사하게 키(Key)와 값(Value)을 쌍으로 저장하는 컬렉션이다. Object와의 차이점:Object의 키는 문자열 또는 심볼만 가능하지만,Map은 모든 타입의 값(객체, 함수 등)을 키로 사용할 수 있다. 이는Map이 단순한 데이터 저장을 넘어 값과 값 사이의 관계를 매핑하는 데 더 유연하게 사용될 수 있음을 의미한다. 또한,Map은size속성을 통해 요소의 개수를 쉽게 알 수 있고, 이터러블(Iterable)하여 순서를 보장한다.const userMap = new Map(); const user1 = { name: "Park" }; // 객체를 키로 사용 userMap.set(user1, "Admin");
console.log(userMap.get(user1)); // "Admin"
- 개념:
WeakMap:- 개념:
Map과 거의 동일하지만, 키로 오직 객체 타입만 허용한다. - 핵심 특징 (약한 참조, Weak Reference):
WeakMap의 키는 '약한 참조'로 연결된다. 이는WeakMap외에 해당 객체를 참조하는 곳이 아무 데도 없다면, 가비지 컬렉터(GC)가 그 객체를 메모리에서 제거할 수 있음을 의미한다. 이 때문에WeakMap은 메모리 누수를 방지하면서 객체에 대한 추가 정보(메타데이터)를 저장하는 용도로 적합하다.
- 개념:
값 기반 컬렉션 (Set Collections) - Set, WeakSet
Set:- 개념: 중복을 허용하지 않는 유일한 값들의 집합이다.
NaN과NaN을 같다고 판단하고,+0과-0을 같다고 판단하는 등 값의 유일성을 정확히 판단한다. - 활용: 배열에서 중복된 요소를 제거하는 데 매우 유용하게 사용된다.
const numbers = [1, 2, 2, 3, 4, 4, 5]; const uniqueNumbers = [...new Set(numbers)]; // [1, 2, 3, 4, 5]
- 개념: 중복을 허용하지 않는 유일한 값들의 집합이다.
WeakSet:- 개념:
Set과 유사하지만, 오직 객체 타입의 값만 저장할 수 있다. - 핵심 특징 (약한 참조):
WeakMap과 마찬가지로 값에 대한 '약한 참조'를 가진다.WeakSet에 저장된 객체가 다른 곳에서 더 이상 참조되지 않으면 메모리에서 제거될 수 있다. 특정 객체들의 집합을 관리하되, 메모리 누수 걱정 없이 사용하고 싶을 때 유용하다.
- 개념:
6. JSON (JavaScript Object Notation)
개념: 속성-값 쌍으로 이루어진, 데이터를 교환하기 위한 경량의 텍스트 기반 형식이다. 이름에 'JavaScript'가 들어가지만, 특정 언어에 종속되지 않는 독립적인 포맷이며 오늘날 대부분의 프로그래밍 언어에서 지원한다. 주로 클라이언트와 서버 간 데이터 통신(AJAX, REST API 등)에 널리 사용된다.
주요 메소드:
JSON.stringify(): 자바스크립트 객체를 JSON 형식의 문자열로 변환한다.JSON.parse(): JSON 형식의 문자열을 자바스크립트 객체로 변환한다.
const user = { name: "Park", age: 30 }; const jsonString = JSON.stringify(user); // '{"name":"Park","age":30}' const parsedObject = JSON.parse(jsonString); // { name: 'Park', age: 30 }
7. 국제화 (Internationalization - Intl)
Intl 객체는 언어에 따라 달라지는 문자열 비교, 숫자 서식, 날짜 및 시간 서식 등을 처리하기 위한 ECMAScript 국제화 API의 네임스페이스이다.
Intl.DateTimeFormat: 언어 및 국가별 형식에 맞춰 날짜와 시간을 표현한다.Intl.NumberFormat: 숫자, 통화, 단위 등을 현지 형식에 맞게 표현한다.
const date = new Date();
const amount = 123456.78;
// 미국 형식
const usDate = new Intl.DateTimeFormat('en-US').format(date); // "11/3/2025"
const usCurrency = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount); // "$123,456.78"
// 한국 형식
const krDate = new Intl.DateTimeFormat('ko-KR').format(date); // "2025. 11. 3."
const krCurrency = new Intl.NumberFormat('ko-KR', { style: 'currency', currency: 'KRW' }).format(amount); // "₩123,457"
8. 프로토타입과 생성자 함수
자바스크립트는 클래스 기반 언어가 아닌, 프로토타입 기반 언어이다. 이는 객체들이 클래스로부터 생성되는 것이 아니라, 다른 객체(프로토타입)를 원형으로 삼아 복제하고 확장하는 방식으로 동작함을 의미한다.
- 생성자 함수 (Constructor Function):
new연산자와 함께 사용되어 동일한 구조를 가진 객체를 여러 개 생성하기 위한 함수이다. 관례적으로 함수 이름의 첫 글자를 대문자로 쓴다. - 프로토타입 (Prototype): 모든 함수 객체는 생성될 때
prototype이라는 특별한 속성을 갖는다. 이 프로토타입 속성은 하나의 객체를 가리키며, 이 생성자 함수를 통해 생성된 모든 인스턴스들은 이 프로토타입 객체를 공유한다. 인스턴스들은 이 프로토타입 객체의 속성과 메소드를 마치 자신의 것처럼 사용할 수 있다.
프로토타입 체인과 상속
- 개념: 어떤 객체의 속성이나 메소드에 접근하려 할 때, 먼저 그 객체 자신에게 해당 속성이 있는지 찾는다. 없으면, 그 객체의 프로토타입(
__proto__또는[[Prototype]]내부 슬롯이 가리키는 객체)으로 올라가서 찾는다. 거기에도 없으면 또 그 프로토타입의 프로토타입으로 올라가서 찾는다. 이 과정은 체인의 최상단인Object.prototype에 도달할 때까지 반복된다. 이 연결 구조를 프로토타입 체인이라고 하며, 이것이 자바스크립트에서 상속이 구현되는 핵심 원리이다.
// 생성자 함수
function Person(name) {
this.name = name;
}
// 프로토타입에 메소드를 추가 (메모리 효율성)
Person.prototype.greet = function() {
console.log(`Hello, I'm ${this.name}.`);
};
const person1 = new Person("Park");
const person2 = new Person("Kim");
person1.greet(); // "Hello, I'm Park."
console.log(person1.greet === person2.greet); // true (같은 프로토타입의 함수를 공유)
9. class 문법
ES6에서 도입된 class 문법은 기존의 프로토타입 기반 상속을 더 명확하고 간결하게 표현할 수 있도록 만든 문법적 설탕(Syntactic Sugar)이다. class는 새로운 객체 모델을 도입한 것이 아니라, 내부적으로는 여전히 프로토타입을 기반으로 동작한다.
class Person {
// 생성자 함수 역할
constructor(name) {
this.name = name;
}
// 프로토타입 메소드 역할
greet() {
console.log(`Hello, I'm ${this.name}.`);
}
}
// 상속 (extends, super)
class Developer extends Person {
constructor(name, language) {
super(name); // 부모 클래스의 constructor 호출
this.language = language;
}
code() {
console.log(`I code in ${this.language}.`);
}
}
const dev = new Developer("Lee", "JavaScript");
dev.greet(); // 부모 클래스의 메소드 상속
dev.code();
10. this와 화살표 함수
this: 함수가 호출될 때 결정되는 특별한 키워드로, 함수를 호출한 주체(객체)를 가리킨다.this는 어떻게 호출되었는가에 따라 동적으로 바인딩된다.- 일반 함수 호출: 전역 객체 (
window또는global) - 메소드 호출: 해당 메소드를 소유한 객체
- 생성자 함수 호출: 새로 생성되는 인스턴스
- 일반 함수 호출: 전역 객체 (
화살표 함수 (
=>):this바인딩 문제를 해결하기 위한 강력한 도구이다. 화살표 함수는 자신만의this를 갖지 않는다. 대신, 함수가 선언된 시점의 상위 스코프(Lexical Scope)의this를 그대로 물려받아 사용한다. 이 때문에 콜백 함수 등에서this가 예기치 않게 변경되는 문제를 피할 수 있다.
11. 스코프 (Scope)
스코프는 변수와 함수에 접근할 수 있는 유효 범위를 의미한다.
- 전역 스코프 (Global Scope): 코드 어디에서든 접근 가능하다.
- 함수 스코프 (Function Scope): 함수 내에서만 접근 가능하다 (
var의 스코프). - 블록 스코프 (Block Scope):
{...}블록 내에서만 접근 가능하다 (let,const의 스코프).
12. 클로저 (Closure)
클로저는 함수와 그 함수가 선언된 어휘적 환경(Lexical Environment)의 조합이다. 더 쉽게 말해, 외부 함수의 실행이 종료되어 소멸된 후에도, 내부 함수가 외부 함수의 변수(자유 변수)를 기억하고 계속해서 접근할 수 있는 현상 또는 그 함수 자체를 말한다. 클로저는 상태를 은닉(정보 은닉)하고 특정 함수에만 상태 변경을 허용하는 캡슐화를 구현하는 데 핵심적인 역할을 한다.
function createCounter() {
let count = 0; // 외부에서 접근 불가한 은닉된 상태
return function() { // 이 내부 함수가 바로 클로저이다.
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
13. 실행 컨텍스트 (Execution Context)
실행 컨텍스트는 코드가 실행되기 위해 필요한 환경 정보들을 모아놓은 객체이다. 자바스크립트 엔진이 코드를 실행할 때, 실행 컨텍스트를 생성하여 콜 스택(Call Stack)에 쌓는다.
- 구성 요소:
- 변수 객체 (Variable Object):
var로 선언된 변수, 함수 선언, 매개변수(arguments) 등을 저장한다. - 스코프 체인 (Scope Chain): 현재 컨텍스트에서 참조할 수 있는 상위 컨텍스트들의 변수 객체에 대한 연결 리스트. 스코프 체인을 통해 상위 스코프의 변수에 접근할 수 있다.
this값: 현재 컨텍스트의this가 무엇인지에 대한 참조.
- 변수 객체 (Variable Object):
자바스크립트 엔진은 코드를 실행하면서 함수를 호출할 때마다 새로운 실행 컨텍스트를 생성하여 스택의 최상단에 쌓고, 함수 실행이 끝나면 해당 컨텍스트를 스택에서 제거한다. this, 스코프, 클로저와 같은 자바스크립트의 핵심 동작 원리는 모두 이 실행 컨텍스트의 개념 위에서 설명될 수 있다.