* 프로그래머스, 타입스크립트로 함께하는 웹 풀 사이클 개발(React, Node.js) 5기 강의 수강 내용을 정리하는 포스팅.
* 원활한 내용 이해를 위해 수업에서 제시된 자료 이외에, 개인적으로 조사한 자료 등을 덧붙이고 있음.
JavaScript는 여타 프로그래밍 언어와 다르게, 스크립트 언어에서 시작해서 프로그래밍 언어로 진화한 독특한 특징을 지니고 있다.
따라서 JavaScript만 배운 사람이라고 하면, 프로그래밍적 사고를 기르는 것이 어렵다.
모든 프로그래밍 언어는 입력을 처리하여 출력하는 공통적인 흐름(입력 → 처리 → 출력)을 기반으로 동작한다.
기본적으로 조건문, 반복문, 함수와 같은 핵심적인 구조와 원리를 공유한다.
따라서 하나의 언어를 깊이 이해하면, 다른 언어로 전환하거나 학습하는 데 필요한 노력이 줄어든다.
// javaScript의 if 조건문은 Python, C, Java 등에서도 거의 동일한 방식으로 작동한다.
// JavaScript
if (x > 0) {
console.log("양수입니다.");
}
# Python
if x > 0:
print("양수입니다.")
자바스크립트는 동적 타입 언어로, 명시적 타입 선언이 없고 런타임에서 타입이 결정된다.
포인터, 메모리 관리 등 저수준 프로그래밍 개념이 추상화되어 있어 개발자가 직접적으로 동작 원리를 경험하기 어렵다.
예를 들어, 메모리 할당 및 해제는 자바스크립트에서 Garbage Collector가 자동으로 처리하지만, C 같은 언어에서는 개발자가 직접 관리해야 한다.
변수의 타입도 마찬가지. let과 const만 존재하는 JavaScript와 달리, 다른 언어들은 숫자를 다루는 타입만 int, long, float, double 등이 존재한다.
// JavaScript:
let x = 10; // 동적 타입, x는 숫자로 할당됨
// C언어:
int x = 10; // 정적 타입, x는 정수로 선언됨
#include <stdio.h>
int main()
{
printf("Hello World");
return 0;
}
console.log("Hello World");
특성 | C 언어 | JavaScript |
---|---|---|
언어 유형 | 컴파일 언어 | 인터프리터 언어 |
출력 함수 | printf("Hello World"); | console.log("Hello World"); |
필요한 준비 작업 | 컴파일(예: GCC) 후 실행 | 실행 환경(Node.js, 브라우저)만 필요 |
출력 대상 | 터미널(콘솔) | 터미널(콘솔) 또는 브라우저 콘솔 |
코드 구조 | 헤더 파일 및 진입점(main 함수) 필요 | 단순히 console.log 호출로 가능 |
실행 속도 | 컴파일된 실행 파일이 더 빠름 | 해석 중 실행하므로 상대적으로 느림 |
자바스크립트는 고수준 언어로, 많은 저수준 언어의 동작 원리를 추상화하여 사용자가 쉽게 프로그래밍할 수 있도록 설계되었다.
C 언어의 개념인 변수, 데이터타입, 배열, 포인터 등은 자바스크립트 내부적으로 동작 원리에 영향을 준다.
예를 들어, 자바스크립트 객체의 참조는 C 언어의 포인터와 유사하다.
타입스크립트(TypeScript)는 자바스크립트에 정적 타입(static typing)을 추가한 언어이다.
C, Java와 같이 변수와 함수에 타입을 명시적으로 선언하는 방식을 사용하면, 타입스크립트 학습에 더 쉽게 적응할 수 있다.
타입을 명시적으로 선언하면, 코드의 안정성과 가독성이 향상되며, 에러를 사전에 방지할 수 있다.
TypeScript로 작성된 코드는 컴파일 과정을 거쳐 바닐라 JavaScript로 전환된다. 사실상 컴파일 개념이 있는 동적 프로그래밍 언어와 원리가 비슷하다는 뜻.
요구사항 분석: 해결하려는 문제를 이해하고 요구사항을 정의한다.
설계: 프로그램의 구조와 로직을 설계(플로우차트, 의사코드 작성 등).
코딩: 설계에 따라 소스 코드를 작성.
테스트 및 디버깅: 코드의 정확성을 검증하고 오류를 수정.
배포 및 유지보수: 프로그램을 사용자에게 제공하고 업데이트 및 오류 수정.
자세한 내용은 이전 포스팅 - 폭포수 모델과 애자일 방법론 참조.
데이터를 저장하는 메모리 공간의 이름.
어떤 값을 기억할 때, 메모리 주소를 기억하는 것보다는 명확한 의미를 가지는 '문자열'로 기억하는게 더 좋다. 변수라는 형태를 사용하는 이유.
선언 시 데이터 타입을 지정하며, 메모리 크기와 표현 가능한 값의 범위를 결정.
int a = 10; // 정수형 변수
float b = 3.14; // 실수형 변수
char c = 'A'; // 문자형 변수
int a = 10, b = 20;
int sum = a + b; // 산술 연산
if (a < b) { // 관계 연산
printf("a는 b보다 작다.\n");
}
컴퓨터 프로그램이 실행될 때, 메모리는 코드 영역, 스택 영역, 힙 영역, 데이터 영역으로 나뉜다.
각 영역은 메모리에서 서로 다른 역할을 하며, 변수와 실행 명령어 등을 저장하는 데 사용된다.
실행할 명령어(코드)를 저장하는 영역이다.
컴파일된 프로그램의 바이너리 코드가 이 영역에 로드된다.
보통 읽기 전용으로 설정되어 있어 실행 중에 수정할 수 없다.
함수의 코드, 제어문 등이 저장된다.
수정이 불가능하므로 프로그램의 안정성을 높인다.
int main() { ... }과 같은 함수의 기계어 코드.
함수 호출과 관련된 지역 변수와 매개변수를 저장한다.
함수가 호출되면 새로운 스택 프레임이 생성되고, 함수 실행이 종료되면 스택 프레임이 제거된다.
메모리가 자동으로 관리된다.
LIFO(Last In First Out) 구조로 동작.
스택 오버플로우(Stack Overflow)가 발생할 수 있음 (예: 재귀 호출 무한 루프).
void func() {
int localVar = 10; // 스택에 저장
}
동적 메모리 할당을 위해 사용되는 영역이다.
프로그래머가 필요에 따라 메모리를 할당하고, 해제해야 한다.
메모리 크기가 프로그램 실행 중 동적으로 결정된다.
명시적으로 할당(malloc, new)과 해제(free, delete)를 수행해야 한다.
해제를 잊으면 메모리 누수(memory leak)가 발생할 수 있음.
int* ptr = (int*)malloc(sizeof(int)); // 힙에 메모리 할당
*ptr = 10; // 값 저장
free(ptr); // 메모리 해제
프로그램 실행 동안 유지되는 전역 변수와 정적 변수(static 변수)가 저장된다.
초기화된 데이터와 초기화되지 않은 데이터로 나뉜다.
전역 변수와 정적 변수는 프로그램이 실행되는 동안 메모리에 계속 존재.
프로그램이 시작될 때 초기화되며, 종료 시까지 유지된다.
BSS(Block Started by Symbol): 초기화되지 않은 전역 변수, 정적 변수.
Data Segment: 초기화된 전역 변수, 정적 변수.
코드 복사
int globalVar = 10; // 데이터 영역에 저장
static int staticVar = 20; // 데이터 영역에 저장
데이터타입 변수명 = 초기값;
#include <stdio.h>
int main() {
int age = 25; // 정수형 변수 선언 및 초기화
float pi = 3.14; // 실수형 변수 선언 및 초기화
char grade = 'A'; // 문자형 변수 선언 및 초기화
printf("Age: %d\n", age); // Age: 25
printf("Pi: %.2f\n", pi); // Pi: 3.14
printf("Grade: %c\n", grade); // Grade: A
age = 30; // 변수 값 변경
printf("Updated Age: %d\n", age); // Updated Age: 30
return 0;
}
변하지 않는 값을 저장하는 메모리 공간.
프로그램 실행 중 값이 고정되어 변경되지 않음.
상수로 선언된 값은 초기화 이후 변경할 수 없음.
코드의 안정성을 높이며, 값의 무결성을 유지.
const 데이터타입 상수명 = 값;
#define 상수명 값
#include <stdio.h>
int main() {
const float PI = 3.14; // 실수형 상수 선언
printf("Pi: %.2f\n", PI); // Pi: 3.14
// PI = 3.14159; // 오류: 상수 값 변경 불가
return 0;
}
#include <stdio.h>
#define MAX 100 // 상수 정의
int main() {
printf("Max value: %d\n", MAX); // Max value: 100
// MAX = 200; // 오류: #define으로 정의된 상수는 변경 불가
return 0;
}
특성 | 변수 | 상수 |
---|---|---|
값의 변경 | 변경 가능 | 변경 불가능 |
메모리 | 읽기 및 쓰기 가능 | 읽기 전용 |
선언 방식 | 데이터타입 변수명 | const 또는 #define 사용 |
사용 목적 | 가변적인 데이터 저장 | 고정된 값(예: 수학적 상수, 설정 값) 저장 |
예시 | int x = 10; | const int y = 100; 또는 #define Z 200 |
#include <stdio.h>
int main() {
int a, b;
printf("Enter two numbers: ");
scanf("%d %d", &a, &b); // 사용자로부터 입력 받기
int sum = a + b; // 변수 사용
printf("Sum: %d\n", sum);
return 0;
}
변하지 않는 값(예: 수학적 상수, 프로그램 설정 값)을 저장.
코드의 안정성을 높이고 가독성을 향상.
#include <stdio.h>
#define TAX_RATE 0.1 // 세율 정의
int main() {
const float PI = 3.14;
float radius = 5.0;
float area = PI * radius * radius; // 원의 넓이 계산
printf("Area of circle: %.2f\n", area);
float income = 1000.0;
float tax = income * TAX_RATE; // 세금 계산
printf("Tax: %.2f\n", tax);
return 0;
}
변수는 프로그램 실행 중 값이 변경될 수 있는 데이터 저장소.
상수는 프로그램 실행 중 값이 변경되지 않는 데이터 저장소.
const와 #define을 통해 상수를 선언하며, 코드의 안정성을 높이는 데 사용.
변수와 상수를 적절히 활용하면 프로그램의 가독성, 안정성, 유지보수성이 향상된다.