1. 함수 포인터 (Function Pointers)
C/C++의 함수 포인터는 함수의 메모리 주소를 저장하여 호출하는 방식입니다. TypeScript(및 JavaScript)에는 직접적인 포인터 개념이 없지만, 함수를 일급 객체(First-class Citizen)로 취급하므로 유사한 기능을 구현할 수 있습니다.
- 개념: 함수를 변수에 할당하거나, 다른 함수의 인자로 전달하거나, 함수의 반환 값으로 사용할 수 있습니다.
- TS에서의 사용: 함수 시그니처를 타입으로 정의하여 변수에 할당하거나 매개변수 타입을 지정합니다.
// (a: number, b: number) => number 라는 타입 시그니처를 정의
type MathOperation = (a: number, b: number) => number;
// 이 타입 시그니처를 따르는 함수들
const add: MathOperation = (a, b) => a + b;
const subtract: MathOperation = (a, b) => a - b;
// 함수를 변수에 할당 (함수 포인터처럼 동작)
let activeOperation: MathOperation;
activeOperation = add;
console.log(`덧셈 결과: ${activeOperation(10, 5)}`); // 출력: 덧셈 결과: 15
activeOperation = subtract;
console.log(`뺄셈 결과: ${activeOperation(10, 5)}`); // 출력: 뺄셈 결과: 5
// 함수를 인자로 전달
function calculate(x: number, y: number, operation: MathOperation): number {
return operation(x, y);
}
console.log(`콜백 함수 실행 결과: ${calculate(20, 10, add)}`); // 출력: 콜백 함수 실행 결과: 30
2. 구조체 (Structs)
C/C++의 구조체(struct)는 연관된 데이터를 하나의 단위로 묶는 값 타입(Value Type) 데이터 구조입니다. TypeScript에는 struct 키워드가 없지만, interface나 type 별칭을 사용하여 동일한 목적을 달성합니다.
- 개념: 여러 변수를 논리적으로 관련된 하나의 단위로 묶어 관리합니다.
- TS에서의 사용:
interface: 객체의 "모양(shape)"을 정의하며, 클래스가 구현해야 할 규약으로도 사용됩니다. 상속(extends)을 통해 확장이 가능합니다.type: 더 유연하며, 유니언(Union)이나 인터섹션(Intersection) 등 복잡한 타입을 정의할 때 주로 사용됩니다.
// interface를 사용한 구조체 정의
interface Point {
x: number;
y: number;
}
const p1: Point = { x: 10, y: 20 };
// type을 사용한 구조체 정의
type Vector = {
x: number;
y: number;
z: number;
};
const v1: Vector = { x: 5, y: -3, z: 8 };
function printPoint(p: Point) {
console.log(`좌표: (${p.x}, ${p.y})`);
}
printPoint(p1); // 출력: 좌표: (10, 20)
3. 공용체(Union)와 열거형(Enum)
공용체 (Union)
C언어의 공용체는 여러 타입의 변수가 하나의 메모리 공간을 공유하는 기능입니다. TypeScript의 유니언 타입(Union Types, |)은 개념적으로 유사하지만, 메모리 공유가 아닌 "여러 타입 중 하나가 될 수 있음"을 의미합니다.
// string 또는 number 타입의 값을 가질 수 있음
let id: string | number;
id = 101; // OK
id = "user-101"; // OK
// id = false; // Error: Type 'boolean' is not assignable to type 'string | number'.
function printId(value: string | number) {
if (typeof value === "string") {
console.log(`문자열 ID: ${value.toUpperCase()}`);
} else {
console.log(`숫자 ID: ${value}`);
}
}
printId(id); // 출력: 문자열 ID: USER-101
열거형 (Enum)
관련된 상수 값들의 집합에 이름을 부여하는 기능입니다. TypeScript는 enum 키워드를 통해 이 기능을 완벽하게 지원합니다.
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right // 3
}
let move: Direction = Direction.Left;
console.log(move); // 출력: 2
// 문자열 기반 Enum도 가능
enum LogLevel {
Info = "INFO",
Warn = "WARN",
Error = "ERROR"
}
function log(message: string, level: LogLevel) {
console.log(`[${level}] ${message}`);
}
log("디스크 공간 부족", LogLevel.Warn); // 출력: [WARN] 디스크 공간 부족
4. 동적 메모리 할당 (Dynamic Memory Allocation)
C/C++에서는 malloc, new 등으로 직접 메모리를 할당하고 free, delete로 해제합니다. TypeScript(JavaScript)는 가비지 컬렉터(Garbage Collector)가 내장된 고수준 언어이므로 개발자가 직접 메모리를 관리하지 않습니다.
- 개념: 프로그램 실행 중에 필요한 만큼의 메모리를 할당받아 사용합니다.
- TS에서의 사용: 객체(
{}), 배열([]), 클래스 인스턴스(new MyClass()) 등을 생성하면 JavaScript 런타임 엔진이 자동으로 메모리를 할당합니다. 더 이상 해당 메모리 주소를 참조하는 변수가 없으면, 가비지 컬렉터가 알아서 메모리를 수거(해제)합니다.
class User {
constructor(public name: string) {
console.log(`${this.name} 객체 생성됨.`); // 이 시점에 메모리 할당
}
}
function createUserList() {
let users: User[] = [];
for (let i = 0; i < 3; i++) {
users.push(new User(`User${i}`)); // 루프마다 새로운 객체가 동적으로 생성
}
return users;
}
let userList = createUserList();
console.log(userList.length); // 출력: 3
// userList 참조가 사라지면 가비지 컬렉터가 관련 객체들을 메모리에서 해제합니다.
5. 객체 지향 프로그래밍 (OOP)
TypeScript는 JavaScript에 정적 타입과 함께 강력한 객체 지향 프로그래밍 기능을 추가한 언어입니다. 아래의 개념들은 모두 TS에서 핵심적인 역할을 합니다.
- 추상화 (Abstraction): 복잡한 내부 구현은 숨기고, 사용자에게는 필수적인 기능(인터페이스)만 노출하는 것입니다. TypeScript에서는
interface나abstract class를 통해 구현합니다. - 캡슐화 (Encapsulation): 데이터(속성)와 해당 데이터를 처리하는 함수(메서드)를 하나의 객체로 묶고, 데이터의 외부 직접 접근을 제한하는 것입니다.
private,protected,public접근 제어자를 사용해 구현합니다. - 클래스 (Class): 객체를 생성하기 위한 "틀" 또는 "설계도"입니다. 속성(properties)과 메서드(methods)를 포함합니다.
- 생성자 (Constructor): 클래스로부터 객체를 생성(인스턴스화)할 때 호출되는 특별한 메서드입니다. 객체의 초기화를 담당합니다.
- 상속 (Inheritance): 부모 클래스의 속성과 메서드를 자식 클래스가 물려받아 재사용하고 확장하는 기능입니다.
extends키워드를 사용합니다.
통합 예제 코드
// 추상화 (Abstract Class)
abstract class Shape {
constructor(protected name: string) {}
// 구현부가 없는 추상 메서드. 자식 클래스는 반드시 구현해야 함.
abstract getArea(): number;
// 일반 메서드
printName() {
console.log(`도형 이름: ${this.name}`);
}
}
// 상속 (Inheritance)
class Rectangle extends Shape {
// 캡슐화 (private 접근 제어자)
private width: number;
private height: number;
// 생성자 (Constructor)
constructor(name: string, width: number, height: number) {
super(name); // 부모 클래스의 생성자 호출
this.width = width;
this.height = height;
}
// 추상 메서드 구현
getArea(): number {
return this.width * this.height;
}
}
// 클래스를 이용해 객체 생성
const rect = new Rectangle("사각형", 10, 5);
rect.printName(); // 출력: 도형 이름: 사각형
console.log(`넓이: ${rect.getArea()}`); // 출력: 넓이: 50
// console.log(rect.width); // Error: Property 'width' is private and only accessible within class 'Rectangle'.
6. 오버로딩 (Overloading) 과 오버라이딩 (Overriding)
- 오버로딩 (Overloading): 하나의 클래스 내에서 같은 이름의 메서드를 다른 매개변수의 타입, 개수, 순서로 여러 개 정의하는 것입니다. TypeScript에서는 전통적인 방식의 메서드 오버로딩 대신, 함수 시그니처 선언과 하나의 구현부로 표현합니다.
- 오버라이딩 (Overriding): 자식 클래스가 부모 클래스로부터 상속받은 메서드를 자신에게 맞게 재정의하는 것입니다.
class Calculator {
// 오버로딩 (Overloading): 선언부만 여러 개, 구현부는 하나
add(a: number, b: number): number;
add(a: string, b: string): string;
// 구현부
add(a: any, b: any): any {
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
}
if (typeof a === 'string' && typeof b === 'string') {
return a + b;
}
}
// 오버라이딩될 메서드
getDescription(): string {
return "일반 계산기";
}
}
class ScientificCalculator extends Calculator {
// 오버라이딩 (Overriding)
override getDescription(): string { // `override` 키워드는 TS 4.3부터 지원
return "과학용 계산기";
}
}
const calc = new Calculator();
console.log(`숫자 덧셈: ${calc.add(5, 10)}`); // 출력: 숫자 덧셈: 15
console.log(`문자열 덧셈: ${calc.add("Hello", " World")}`); // 출력: 문자열 덧셈: Hello World
const sciCalc = new ScientificCalculator();
console.log(sciCalc.getDescription()); // 출력: 과학용 계산기
7. 인터페이스 (Interface)
객체의 구조나 클래스가 따라야 할 규약(contract)을 정의합니다. TypeScript의 인터페이스는 코드 변환 시 사라지며, 오직 타입 체크와 개발 편의를 위해 존재합니다.
- 역할:
- 객체의 형태(shape)를 정의 (구조체 역할).
- 클래스가 특정 메서드나 속성을 갖도록 강제 (
implements키워드 사용).
interface Serializable {
toJson(): string;
}
class Product implements Serializable {
constructor(public name: string, public price: number) {}
// 인터페이스 규약 준수
toJson(): string {
return JSON.stringify({ name: this.name, price: this.price });
}
}
const book = new Product("TypeScript 가이드", 30000);
console.log(book.toJson()); // 출력: {"name":"TypeScript 가이드","price":30000}
8. 람다식 (Lambda Expressions)
람다식은 익명 함수(anonymous function)를 간결하게 표현하는 방법입니다. TypeScript에서는 화살표 함수(Arrow Functions, =>)가 람다식의 역할을 합니다.
- 특징:
- 간결한 문법.
this가 함수가 선언된 시점의 컨텍스트를 그대로 유지(Lexicalthis). 이는 일반function키워드와의 가장 큰 차이점입니다.
const numbers = [1, 2, 3, 4, 5];
// 일반 함수 사용
const squared1 = numbers.map(function(n) {
return n * n;
});
// 화살표 함수(람다식) 사용
const squared2 = numbers.map(n => n * n);
console.log(squared2); // 출력: [1, 4, 9, 16, 25]
// 'this' 컨텍스트 예제
class Greeter {
message = "Hello, World!";
greet() {
// 화살표 함수는 greet() 메서드와 동일한 'this'를 가리킴
setTimeout(() => {
console.log(this.message); // 정상 출력
}, 1000);
}
}
const greeter = new Greeter();
greeter.greet(); // 1초 후 "Hello, World!" 출력'Programmers' 카테고리의 다른 글
| [42일차]타입스크립트: 언어 개념과 기본 설정. (0) | 2025.11.10 |
|---|---|
| [과제] Book Market 프로젝트 결과 보고서 (0) | 2025.11.06 |
| [40일차] C언어와 JavaScript의 메모리 관리 및 포인터 (0) | 2025.11.05 |
| [39일차]프로그래밍 기초 개념, 컴파일 언어, 메모리 구조, 변수와 상수 (0) | 2025.11.04 |
| [37일차]프론트엔드 커리큘럼의 시작, JS 기초 (0) | 2025.11.02 |