JavaScript

j0yy00n0·2025년 5월 1일

2025.04.02

JavaScript

JavaScript

인터프리터형 프로그래밍 언어

  • 주로 웹 개발에서 사용
  • 웹 페이지에 동적 기능을 추가
  • 객체 기반(Object-Based) 언어
    - 객체의 개념을 지원하지만 순수 객체지향 언어와 다르게 클래스 없이 객체를 생성할 수 있다.
  • 멀티 패러다임
    - 명령형, 함수형, 객체지향 프로그래밍 스타일을 지원

주요 특징

  1. 클라이언트 사이드 언어
    • 웹 브라우저에서 실행되어 사용자와 상호작용
  2. 비동기 처리
    • 콜백 함수, 프라미스(Promise), async/await를 이용해 동기적/비동기적 처리
  3. 이식성
    • 브라우저에 종속되지 않으며 다양한 플랫폼에서 사용 가능
  4. 동적 타입 언어
    • 변수 선언 시 자료형이 고정되지 않는다.
  5. 표준화
    • ECMA International에 의해 ECMAScript(ES) 표준으로 관리

자바스크립트 환경 설정

  • Node.js 설치
    - 자바스크립트 런타임 환경
    • 브라우저가 없어도 로컬 컴퓨터에서 자바스크립트를 실행할 수 있다.
  • VS Code(Visual Studio Code) 설치
    - 코드를 작성하고 관리하는 데 사용하는 통합 개발 환경(IDE)

변수와 데이터 저장

키워드

  • var : 함수 스코프를 가지며, 중복 선언이 가능(사용 자제 권장)
  • let : 블록 스코프를 가지며, 재할당이 가능
    - 반복 횟수를 카운트 하는 변수에 주로 사용
  • const : 블록 스코프를 가지며, 재할당이 불가능
    - 상수 값이나 객체를 저장하는데 주로 사용
let name = "Alice";
const age = 25;

변수의 스코프

스코프는 변수가 어디에서 접근 가능한지를 결정
Node.js 환경에서의 스코프는 전역 스코프와 블록 스코프가 존재

  • 블록 스코프
{
    let blockScoped = "블록 안에서만 접근 가능";
    console.log(blockScoped); 
}
  • 전역 스코프
var globalScoped = "전역에서 접근 가능";
{
    console.log(globalScoped); // 출력: 전역에서 접근 가능
}

변수 선언 규칙과 스타일

  • 변수 이름은 알파벳, 숫자, _, $만 사용
  • 숫자로 시작할 수 없다.
  • 카멜케이스(camelCase) 사용이 일반적
  • 예약어 사용 금지
  • 대소문자 구분
  • 의미 있는 이름 사용 권장
  • 상수 변수 선언 시 대문자, 언더스코어 사용하는 것이 일반적

자료형

원시 자료형 (Primitive Data Types)

더 이상 나눌 수 없는 단일 값

  • Number : 실수와 정수를 구분하지 않는다
  • String : java와 다르게 참조자료형이 아닌 원시 자료형 , 문자라는 것은 없고 다 문자열
  • 자바스크립트 문자열 표현 방식 : ``, "", ''
let emptyValue = null;
let uninitialized;
console.log(emptyValue); <!-- 출력: null -->
console.log(uninitialized); <!-- 출력: undefined -->

<!-- Infinity: 무한대 -->
console.log(1 / 0); <!-- 출력: Infinity -->

<!-- NaN (Not-a-Number) : 수학적으로 정의되지 않은 연산의 결과 -> 연산을 수행할 수 없다 -->
console.log("text" * 2); <!-- 출력: NaN -->

객체 자료형

키-값 쌍(Key-Value Pair)으로 데이터를 저장하는 구조

  • 객체는 데이터를 구조적으로 관리하기 위해 설계된 자료형
  • 메모리의 힙(heap) 영역에 데이터를 저장하고 참조(reference)를 통해 이를 관리

객체(Object) : 키-값 쌍으로 데이터를 저장 {}
배열(Array) : 순서가 있는 데이터의 집합 []
다차원 배열 : 여러 차원의 데이터를 저장하는 구조, 행과 열로 구성
함수(Function) : 실행 가능한 코드 블록 function()
객체 배열 : 배열과 객체를 조합 [{}]

  • 자바스크림트의 함수는 자바에서 메소드라고 생각, 메소드 자체를 객체로써 인식한다고 생각

메모리 관리

  • 객체 자료형은 참조 방식으로 동작
  • 변수를 복사할 경우, 객체 자체가 아닌 메모리 주소를 복사하여 동일한 데이터를 참조
  • 변수 영역은 식별자와 값의 주소를 저장한다.
  • 데이터 영역은 데이터의 값을 저장한다.
let original = { name: "Alice", age: 25 };
let copy = original; <!-- 메모리 주소를 복사 -->
copy.name = "Bob";

console.log(original.name); <!-- 출력: Bob (original도 영향을 받음) -->
<!-- 함수 : function () -->
let greet = function () {
  return "Hello!";
};
console.log(greet()); <!-- 출력: Hello! -->
<!-- 객체 배열 -->
<!-- 객체 배열 안에는 같은 자료형이 아니라도 같이 쓸 수 있다 -->
let students = [
    { name: "Alice", age: 20, score: 85 },
    { name: "Bob", age: 22, score: 90 },
    { name: "Charlie", age: 19, score: 78 }
    0,
    function() {},
    [],
    NaN
];

typeof 연산자

변수나 값의 자료형을 확인하는 데 사용

console.log(typeof null); <!-- 출력: "object" (JavaScript의 오래된 버그) -->
console.log(typeof [1, 2, 3]); <!-- 출력: "object" (배열도 객체의 일종) -->

자료형 변환

동적 타입

변수에 저장된 값에 따라 자료형이 자동으로 할당
-> 변수 선언이 아닌 할당에 의해 타입이 결정
-> 재할당에 의해 변수의 타입은 언제든지 동적으로 변할 수 있다.

  • 유연성은 높지만 신뢰성은 떨어진다.
let test; 
<!-- test 변수를 선언하였으나 값을 설정하지 않았으므로 
	 빈 값을 의미하는 undefined 타입이 됨 -->

test = 1; 
<!-- 이전 시점에 test 변수는 undefined였으나, 
	 숫자 1이 할당됨으로써 test의 타입은 Number로 변경됨 -->

test = "1"; 
<!-- "" <- 문자열을 의미하며 "", '' 으로 감싸진 값은 문자열로 취급이 된다. -->
<!-- test 변수에 문자열 "1"가 할당됨으로써, test의 타입은 String으로 변경됨 -->

test = true; 
<!-- test 변수에 Boolean 값 true가 할당되면서, 
	 test의 타입은 Boolean으로 변경됨 -->

test = null; 
<!-- test 변수에 null이 할당되면서, 
	 test의 타입은 다시 null로 변경됨 -->

test = { name: "Alice" }; 
<!-- test 변수에 객체가 할당되면서, 
	 test의 타입은 Object로 변경됨 -->

test = [1, 2, 3]; 
<!-- test 변수에 배열이 할당되면서, 
	 test의 타입은 Array(객체의 한 종류)로 변경됨 -->

암묵적 변환 (묵시적 형변환)

  • 문자열과 숫자의 연산
    - 장점 : 코드 간결, 자동변환
    • 단점 : 변환 과정이 명확하지 않아 코드 가독성이 떨어질 수 있음, 데이터가 예상치 못한 방식으로 처리될 위험
console.log(10 + "20"); 
<!-- 출력: "1020" (숫자가 문자열로 변환되어 연결) -->
console.log("10" * 2); 
<!-- 출력: 20 ("10"이 숫자로 변환되어 계산) -->
    1. 단항 플러스 연산자 : 주로 변수를 숫자로 변환하는 데 사용
<!-- 문자열이 숫자로 암묵적으로 변환 -->
<!-- 단항 플러스 연산자 : 주로 변수를 숫자로 변환하는 데 사용 -->
totalScore = +student1Score + +student2Score + +student3Score;
console.log("학생 평균 점수:", totalScore / 3); <!-- 출력: 85 -->
    1. 문자열 형식의 숫자 값에 - 0 연산을 이용해서 숫자로 형변환 : 문자열이 숫자로 변환되어 비교
let isStudent1Adult = student1Age - 0 >= 18;
let isStudent2Adult = student2Age - 0 >= 18;
  • 불리언 변환
    - Falsy로 변환되는 값: 0, "", null, undefined, NaN, false.
    • 나머지는 Truthy (true로 변환)
    • 자바스크립트는 Truthy / Falsy 개념이 있어서 불리언이 아닌 값도 논리 연산에 사용 가능
console.log(Boolean(0)); <!-- 출력: false -->
console.log(Boolean("Hello")); <!-- 출력: true -->
console.log(Boolean("")); <!-- 출력: false -->

명시적 변환

명확성과 데이터 일관성 유지, 코드의 안정성이 높아진다.

  • 숫자로 변환
    - Number()를 사용하여 문자열이나 불리언을 숫자로 변환
console.log(Number("42")); <!-- 출력: 42 -->
console.log(Number("Hello")); <!-- 출력: NaN -->
console.log(Number(true)); <!-- 출력: 1 -->
console.log(Number(false)); <!-- 출력: 0 -->
  • 문자열로 변환
    - String()을 사용하여 숫자나 불리언을 문자열로 변환
console.log(String(42)); <!-- 출력: "42" -->
console.log(String(true)); <!-- 출력: "true" -->
  • 불리언으로 변환
    - Boolean()을 사용하여 값을 불리언으로 변환
console.log(Boolean(1)); <!-- 출력: true -->
console.log(Boolean(0)); <!-- 출력: false -->
console.log(Boolean("")); <!-- 출력: false -->

연산자와 표현식

산술 연산자 (Arithmetic Operators)

대입 연산자

비교 연산자 (Comparison Operators)

동등성 비교

==와 ===의 차이

  • ==(동등 연산자) : 값만 비교하며, 필요시 타입을 암묵적으로 변환하여 비교
    - 문자열 "10"과 숫자 10은 동등(true)
  • ===(일치 연산자):값과 타입을 모두 비교
    - 문자열 "10"과 숫자 10은 타입이 다르므로 일치하지 않는다(false)

!=와 !==의 차이

  • !=(부등 연산자) : 값만 비교하며, 필요시 타입을 암묵적으로 변환
  • !==(불일치 연산자) : 값과 타입을 모두 비교

논리 연산자 (Logical Operators)

단축 평가

조건의 평가를 최소화하여 효율성을 높이는 기법

  • || (OR) : 첫 번째 조건이 true라면 두 번째 조건은 평가하지 않는다
  • && (AND) : 첫 번째 조건이 false라면 두 번째 조건은 평가하지 않는다.
  • ?? (Nullish Coalescing) : null 또는 undefined인 경우 기본값을 설정
    - value ?? defaultValue는 value가 null 또는 undefined일 때만 defaultValue를 반환

삼항 연산자

(조건문) ? 참일 때 값 : 거짓일 때 값


조건문

if문

조건이 참(true)일 때 실행되는 코드 블록을 정의

  • if문
if (조건) { 
    // 조건이 참일 때 실행할 코드
}
  • else if 문 : 이전 조건이 거짓일 때 다음 조건을 확인
else if (조건) {
    // 추가 조건이 참일 때 실행할 코드
}
  • else 문 : 모든 조건이 거짓일 경우 실행되는 코드 블록
else {
    // 모든 조건이 거짓일 때 실행할 코드
}

switch문

주어진 표현식의 값을 평가하여 여러 경우(case) 중 하나에 해당하는 코드 블록을 실행하는 제어 구조

  • switch 문은 여러 조건을 처리할 때, if-else 문보다 가독성이 높고 관리하기 쉬운 경우가 많다
switch (표현식) {
       case 값1:
           // 값1과 일치할 때 실행할 코드
           break;
       case 값2:
           // 값2와 일치할 때 실행할 코드
           break;
       default:
           // 모든 case와 일치하지 않을 때 실행할 코드
   }
  • switch 문: 평가할 표현식을 지정
  • case: switch 문에서 검사할 각 경우를 정의
  • break: 각 case 블록이 실행된 후 switch 문을 종료, break가 없으면 다음 case 블록이 계속 실행
  • default: 모든 case와 일치하지 않을 때 실행되는 코드 블록, 선택 사항

반복문 종류

for문

반복 횟수가 명확할 때 사용

  • 초기화, 조건 검사, 증감 연산을 한 곳에서 처리
for (let i = 0; i < 10; i++) {
    console.log(i);
}
  • 반복 변수에는 let을 사용하는 것이 일반적,const는 값을 변경할 수 없기 때문에 증감 불가능

while문

조건이 참인 동안 반복

  • 조건이 거짓이 되면 종료
let i = 0;
while (i < 10) {
    console.log(i);
    i++;
}

do-while문

최소 한 번은 실행한 후 조건을 검사해 반복 여부를 결정

let j = 0;
do {
    console.log(j);
    j++;
} while (j < 10);

반복문 제어

break

특정 조건에서 반복문을 중단한다.

let searchCart = [1200, 1500, 3000, 4500, 5000];
let searchTotal = 0;

for (let i = 0; i < searchCart.length; i++) {
    if (searchCart[i] === 3000) {
        console.log("3000원 상품 발견! 계산 중단.");
        break; // 반복문 종료
    }
    searchTotal += searchCart[i];
}

console.log(`계산된 총 가격: ${searchTotal}원`);

continue

특정 조건에서 반복문을 건너뛴다.

let selectiveCart = [1200, 1500, 3000, 4500, 800];
let selectiveTotal = 0;

for (let i = 0; i < selectiveCart.length; i++) {
    if (selectiveCart[i] <= 1000) {
        continue; // 1000원 이하 상품 건너뜀
    }
    selectiveTotal += selectiveCart[i];
}

console.log(`1000원 초과 상품 총 가격: ${selectiveTotal}원`);

함수

특정 작업이나 계산을 수행하는 코드 블록으로, 입력값을 받아 처리한 후 결과를 반환하는 구조

  • 함수는 프로그래밍에서 코드의 재사용성과 가독성을 높이는 데 중요한 역할
  • 독립적인 단위로, 필요할 때마다 호출하여 사용할 수 있다(재사용 가능)

함수 선언

function 키워드를 사용하여 선언

  • 함수 이름, 매개변수, 함수의 구현 내용을 정의
function 함수이름(매개변수1, 매개변수2, ...) {
    // 함수가 수행할 코드
    return 반환값; // 선택 사항
}

function add(a, b) {
    return a + b; // 두 매개변수의 합을 반환
}

함수 호출

함수 이름과 괄호를 사용

  • 괄호 안에는 함수에 전달할 인수를 넣을 수 있다
  • java의 객체 + method가 합쳐진 것으로 인지하면 좋다.
함수이름(인수1, 인수2, ...);

let result = add(5, 10); // add 함수를 호출하여 5와 10을 전달

함수의 매개변수와 인수

매개변수: 함수 선언 시 정의하는 변수

  • 함수가 호출될 때 전달되는 값

인수: 함수를 호출할 때 전달하는 실제 값

function 함수이름(매개변수1, 매개변수2, ...) {
    // 함수가 수행할 코드
    return 반환값; // 선택 사항
}

함수이름(인수1, 인수2, ...);

기본 매개변수

함수의 매개변수에 기본값을 설정할 수 있다.

  • 인수가 전달되지 않았을 때 기본 값을 사용할 수 있다.
function multiply(a, b = 1) {
    return a * b; // b가 전달되지 않으면 기본값 1 사용
}

console.log(multiply(5)); // 5 출력
console.log(multiply(5, 2)); // 10 출력

함수 표현식

함수를 변수에 할당하여 사용할 수 있는 방식

  • 함수 선언식과 달리 호출 전에 정의되어야 한다
const functionName = function(parameters) {
    // 함수 본문
    return value;
};

화살표 함수

간결한 문법으로 함수를 정의

  • this 바인딩 방식이 일반 함수와 다르다
  • 일반 함수 : 실행 컨텍스트에 따라(호출 위치에 따라) 동적으로 this를 설정(자기 자신)
  • 화살표 함수 : 선언 시점의 this를 고정적으로 유지, 선언된 위치의 상위 스코프를 참조(global 전역)
const functionName = (parameters) => {
    // 함수 본문
    return value;
};

function f() {};
const f = () => {};
const obj = {
    value: 100,
    regularFunction: function() {
        console.log("일반 함수 this:", this.value); // `obj`를 가리킴
    },
    arrowFunction: () => {
        console.log("화살표 함수 this:", this.value); // 상위 스코프의 `this`를 가리킴
    }
};

obj.regularFunction(); // 일반 함수 this: 100
obj.arrowFunction(); // 화살표 함수 this: undefined
name = "전역 이름"; // var name = ... 처럼 전역에 추가됨

const user = {
  sayHi2: () => {
    console.log(this.name);
  },
};

user.sayHi2(); // "전역 이름"

일급 객체(First-Class Object)로서의 함수

자바스크립트의 함수는 일급 객체이다.
프로그래밍 언어에서 객체가 가지는 특성을 나타내는 용어

  • 변수에 할당될 수 있다.
const sayHi = function() {
  console.log("안녕하세요!");
};

sayHi();  // 출력: 안녕하세요!
  • 다른 함수의 매개변수로 전달될 수 있다.
function greet(fn) {
  fn(); // 전달받은 함수 실행
}

greet(function() {
  console.log("반가워요!");
});
  • 다른 함수의 반환값으로 사용될 수 있다.
function getGreeting() {
  return function() {
    console.log("좋은 하루!");
  };
}

const hello = getGreeting();
hello();  // 출력: 좋은 하루!
  • 프로그램 실행 중에 동적으로 생성할 수 있다.

스코프와 클로저 기초

스코프

변수와 함수가 유효한 범위를 정의

함수 스코프
함수 내부에서 선언된 변수는 함수 외부에서 접근할 수 없다.

  • var 키워드는 함수 스코프를 따른다
function scopeExample() {
    var a = "함수 내부";
    console.log(a); // 출력: "함수 내부"
}
console.log(a); // 에러: a is not defined

블록 스코프
블록 내부에서 선언된 변수는 블록 외부에서 접근할 수 없다.

  • let, const는 블록 스코프를 따른다.
{
    let b = "블록 내부";
    const c = "블록 내부";
    console.log(b, c); // 출력: "블록 내부 블록 내부"
}
console.log(b, c); // 에러: b, c is not defined

클로저

함수와 함수가 선언될 당시의 렉시컬 환경(Lexical Environment)을 기억하는 기능

  • 함수가 생성될 때 외부 스코프를 캡처하여, 함수가 실행되는 동안에도 외부 스코프에 접근할 수 있도록한다.
function outerFunction(outerVariable) {
    return function innerFunction(innerVariable) {
        console.log(`Outer: ${outerVariable}, Inner: ${innerVariable}`);
    };
}

const closureExample = outerFunction("Outside");
closureExample("Inside"); // 출력: Outer: Outside, Inner: Inside

콜백 함수

함수의 인수로 전달되어 특정 작업이 완료된 후 호출되는 함수
다른 함수에 인자로 전달되어 그 함수 내부에서 호출되는 함수

  • 주로 비동기 작업에서 사용
  • 이벤트 처리, 데이터 처리 등 다양한 용도로 활용
  • 실행 흐름을 제어
  • 코드의 재사용성과 가독성을 높이는 데 기여
  • 콜백 지옥
    - 여러 개의 비동기 작업이 서로 연결되어 실행될 때 콜백 함수가 중첩되어 가독성이 떨어지는 상태를 의미
// 콜백 함수 사용 기본 형태
function higherOrderFunction(callback) {
    console.log("작업 시작...");
    callback(); // 작업 완료 후 콜백 함수 실행
    console.log("작업 종료.");
}

// 콜백 함수 정의
function myCallback() {
    console.log("콜백 함수 호출됨!");
}

// 실행
higherOrderFunction(myCallback);

<!-- 출력 -->
작업 시작...
콜백 함수 호출됨!
작업 종료.

고차 함수

콜백 함수를 인수로 받거나 다른 함수를 반환하는 함수


객체(Object)

키-값 쌍으로 구성된 데이터 구조

  • 객체는 다양한 데이터를 하나의 단위로 묶는다,
  • 객체 내부의 값은 property(속성)
  • 각 데이터에 이름(키)을 통해 접근

객체 생성

객체 리터럴

const person = {
    name: '홍길동',
    age: 30,
    job: '개발자'
};

Object 생성자

const person = new Object();
person.name = '홍길동';
person.age = 30;
person.job = '개발자';

객체의 속성 접근

점 표기법

console.log(person.name); // 홍길동

대괄호 표기법

console.log(person['age']); // 30

속성 삭제

  • delete 객체.속성
  • splice(): 특정 인덱스의 객체를 삭제

객체의 메서드

데이터뿐만 아니라 함수를 포함

const calculator = {
    add: function(a, b) {
        return a + b;
    }
};

console.log(calculator.add(5, 3)); // 8

배열 (Array)

순서가 있는 데이터의 집합

  • 자바스크립트에서 배열은 객체의 특수한 형태
  • 배열은 다양한 타입의 데이터를 저장 가능
  • 배열의 각 요소는 인덱스를 통해 접근

배열 생성

배열 리터럴

const fruits = ['사과', '바나나', '체리'];

Array 생성자

const fruits = new Array('사과', '바나나', '체리');

배열의 요소 접근

  • push(): 배열의 끝에 요소 추가
  • pop(): 배열의 마지막 요소 제거 후 반환
  • forEach(): 배열의 각 요소에 대해 함수를 실행
  • flat(): 중첩 배열을 단일 배열로 변환(중복 삭제하지 않음)
fruits.forEach(fruit => {
    console.log(fruit);
});
  • map(): 배열의 각 요소를 변형한 새로운 배열 생성
const lengths = fruits.map(fruit => fruit.length);

JSON(JavaScript Object Notation)

데이터를 키-값 쌍으로 저장하는 경량 데이터 교환 형식

  • 자바스크립트 객체와 유사
  • 텍스트 기반이므로 가독성과 데이터 교환의 효율성이 높다
  • 웹 애플리케이션과 서버 간 데이터를 주고받는 데 자주 사용

JSON과 자바스크립트 객체의 차이

  1. 정의 및 형식
  • 자바스크립트 객체
    - 자바스크립트의 데이터 구조

    • 함수, 배열, 다른 객체 등을 포함
  • JSON
    - 텍스트 기반의 데이터 형식

    • 데이터 전송 및 저장에 적합
    • 문자열 형태로 존재
    • 함수나 메서드를 포함할 수 없다
      {
          "name": "홍길동",
          "age": 30
      }
  1. 사용 용도
  • 자바스크립트 객체
    - 주로 코드 내에서 데이터 구조를 정의하고 조작하는 데 사용
    • 객체는 프로그램의 상태를 유지하거나 기능을 구현하는 데 중요한 역할
  • JSON
    - 클라이언트와 서버 간의 데이터 교환, API 응답, 파일 저장 등에 주로 사용
  1. 변환
  • 객체 -> JSON 변환
    - 직렬화
    - JSON.stringify() 메서드를 사용

    JSON.stringify(객체, replacer, space);
    

    - 객체 : 문자열로 반환할 대상
    - replacer : 어떤 속성을 포함할지 필터링 (보통 null이면 모든 속성 포함)
    - space : 들여쓰기(공백 또는 탭의 수)를 지정 → 가독성을 위한 옵션

  • JSON -> 객체 변환
    - 역직렬화
    - JSON.parse() 메서드를 사용


비동기 처리

프로그램의 일부 작업을 기다리지 않고 다음 작업을 수행할 수 있도록 설계하는 방식

  • setTimeout과 같은 타이머 함수, 이벤트 기반 작업(addEventListener) 등에서 활용
    - setTimeout(callback, delay)
    • addEventListener(event, callback)
  • 자바스크립트의 단일 스레드 환경에서 효율적인 작업 분배를 가능
  • 자바스크립트는 기본적으로 싱글 스레드 환경에서 실행되지만, 비동기 작업을 처리하기 위해 Node.js는 이벤트 루프와 스레드 풀을 활용
  • I/O 작업(파일 읽기, 데이터베이스 쿼리, 네트워크 요청 등)에서 유용
  • 프로그램의 효율성과 반응성을 향상시키는 데 기여

이벤트 루프

메인 스레드에서 실행되는 코드가 완료되면, 이벤트 루프가 이벤트 큐에서 대기 중인 콜백 함수를 처리

  • 비동기 작업의 결과가 준비될 때까지 메인 스레드가 다른 작업을 계속 수행할 수 있도록 해준다

스레드 풀


Node.js는 libuv라는 라이브러리를 통해 블로킹 I/O 작업을 처리하기 위해 백그라운드에서 여러 스레드를 사용하는 스레드 풀을 운영

  • 이 스레드들은 파일 시스템 작업, 네트워크 요청 등과 같은 시간이 걸리는 작업을 처리
  • 완료된 후 메인 스레드로 결과를 전달
// setTimeout을 사용한 비동기 실행
setTimeout(() => {
    console.log("2초 후 실행되었습니다.");
}, 2000);

// addEventListener를 사용한 이벤트 기반 비동기 실행
document.getElementById("myButton").addEventListener("click", () => {
    console.log("버튼이 클릭되었습니다!");
});
  • 코드를 만나면 setTimeout은 바로 실행되지만, 내부 함수는 2초 동안 기다렸다가 나중에 실행
  • 사용자가 버튼을 클릭하면 console.log("버튼이 클릭되었습니다!")가 그때 실행
  • 2초 뒤 console.log("2초 후 실행되었습니다.") 실행

비동기 프로그래밍의 특징

  1. 동시성 (Concurrency)
  • 여러 작업이 동시에 진행
  • 작업이 완료될 때까지 대기하지 않고, 다른 작업을 수행
  1. 콜백 (Callback)
  • 비동기 작업이 완료되면 호출되는 함수를 정의할 수 있다
  1. 프라미스 (Promise)
  • 비동기 작업의 완료를 나타내는 객체
  • 비동기 작업이 성공했을 경우와 실패했을 경우를 처리할 수 있는 메서드를 제공
    - 1. Pending: 대기 중
      1. Fulfilled: 작업 성공
      1. Rejected: 작업 실패
    • then으로 작업 성공 시 실행할 콜백을 등록하고, catch로 에러를 처리
    • try{}catch문처럼 생각하면 된다.
const promise = new Promise((resolve, reject) => {
    // 비동기 작업
    if (/* 성공 조건 */) {
        resolve("작업 성공");
    } else {
        reject("작업 실패");
    }
});

promise
    .then((result) => console.log(result)) // 성공 시 실행
    .catch((error) => console.error(error)); // 실패 시 실행
  1. async/await
  • ES2017(ES8)에서 도입된 구문
  • 비동기 코드를 동기 코드처럼 작성할 수 있게 해준다
  • 가독성을 높이고, 복잡한 콜백 구조를 피할 수 있다
  • async : 함수 앞에 붙이면, 그 함수는 항상 Promise를 반환
  • await : Promise가 끝날 때까지 기다렸다가 결과를 받아옴
async function asyncFunction() {
    const result = await someAsyncTask();
    console.log(result);
}
async function fetchData() {
    return new Promise((resolve) => {
        setTimeout(() => {
            const data = { id: 1, name: '홍길동' };
            resolve(data);
        }, 1000);
    });
}

async function getData() {
    const result = await fetchData();
    console.log('데이터:', result);
}

getData();

<!-- fetchData()는 async 함수이므로 반드시 Promise를 반환
	 내부에서 resolve(data)를 호출하면, 이 Promise는 fulfilled 상태가 되고 data를 전달
     await fetchData(); → fetchData()가 끝날 때까지 기다렸다가 그 결과(data)를 result에 담음
     console.log(...)는 fetchData()가 완료된 후에 실행 -->

비동기 프로그래밍의 장점

  1. 효율적인 자원 사용
  • CPU와 I/O 자원을 효율적으로 사용
  1. 반응성 향상
  • 사용자가 인터페이스를 사용하면서도 데이터 로딩 등의 작업이 백그라운드에서 진행될 수 있다
  1. 확장성
  • 서버와 같은 시스템에서 높은 동시성을 제공
  • 더 많은 요청을 동시에 처리할 수 있게 해준다

이벤트 루프(Event Loop)

비동기 작업을 처리하기 위한 메커니즘

  • 자바스크립트는 싱글 스레드이지만 이벤트 루프를 사용해 비동기 작업을 효율적으로 처리
  1. 콜 스택(Call Stack): 함수 실행 컨텍스트를 저장
  2. 이벤트 큐(Event Queue): 비동기 작업이 완료되면 실행 대기 중인 콜백 함수를 저장
  3. 이벤트 루프(Event Loop): 콜 스택이 비어 있으면 이벤트 큐에서 콜백을 가져와 실행
    • 매크로 테스크 (Macro Task) : 타이머, 네트워크 요청, I/O 작업 등과 같은 비동기 작업이 완료되었을 때 실행되는 작업
    • 마이크로 테스크 (Micro Task) : 프로미스의 .then(), .catch(), .finally()와 같은 비동기 작업의 결과를 처리하는 작업
    • 마이크로 테스크는 매크로 테스크보다 우선적으로 실행
    • 현재 호출 스택이 비어지면, 이벤트 루프는 먼저 마이크로 테스크 큐를 확인하고, 모든 마이크로 테스크가 완료된 후에야 매크로 테스크 큐에서 작업을 실행

setTimeout과 setInterval의 동작 원리

setTimeout: 지정된 시간(ms) 후에 한 번 실행되는 함수

  • setTimeout(callback, delay)
setTimeout(() => {
    console.log("1초 후에 실행");
}, 1000)
const reminder = setTimeout(() => {
    console.log("이 메시지는 출력되지 않습니다.");
}, 5000);

setTimeout(() => {
    clearTimeout(reminder);
    console.log("알림이 취소되었습니다.");
}, 2000);
  • setTimeout()는 clearTimeout()를 써서 중단시킨다.

setInterval: 지정된 시간(ms) 간격으로 반복 실행되는 함수

let count = 0;
const intervalId = setInterval(() => {
    console.log(`Interval 실행: ${++count}`);
    if (count === 5) clearInterval(intervalId); // 5회 실행 후 종료
}, 1000);
  • setInterval()는 clearInterval()를 같이 써서 무한반복하지 않게 한다.
  • 타이머 함수는 비동기적으로 실행되며, 이벤트 루프와 밀접한 관계

ES6

템플릿 리터럴 (Template Literals)

다중 행 문자열과 문자열 보간 기능을 지원

  • 백틱을 사용
  • 문자열 내에서 표현식을 삽입하거나 여러 줄 문자열을 줄바꿈 없이 쉽게 작성
  • ${}를 사용해 문자열 내에 표현식을 삽입
const name = "홍길동";
const greeting = `안녕하세요, ${name}!`;
console.log(greeting); // 안녕하세요, 홍길동!

태그드 템플릿(Tag Template)

태그 함수를 사용해 템플릿 리터럴을 커스터마이징

  • 태그 함수(<>)는 템플릿 리터럴의 문자열과 표현식을 분리해 처리
function formatMessage(strings, ...values) {
    return strings.reduce((result, str, i) => {
        return `${result}${str}${values[i] ? `<b>${values[i]}</b>` : ""}`;
    }, "");
}

const taggedMessage = formatMessage`안녕하세요, ${customerName}님.
주문하신 ${orderItem}의 가격은 ${orderPrice.toLocaleString()}원입니다.`;

console.log(taggedMessage);

디스트럭처링 할당 (Destructuring Assignment)

배열이나 객체에서 값을 쉽게 추출할 수 있는 문법

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

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

모듈 (Modules)

import와 export 키워드를 사용하여 모듈을 정의하고 사용

  • Default Export: 기본 값 내보내기
    - export default
    - 파일당 하나만 사용할 수 있으며, 이름 없이 내보낼 수 있다
  • Utils는 모듈 전체를 객체처럼 받아오는 이름
<!-- export (파일 내보내기) -->
// module.js
export const PI = 3.14;
export function add(a, b) {
    return a + b;
}

<!-- import (파일 가져오기) -->
// main.js
import { PI, add } from './module.js';
console.log(PI); // 3.14
console.log(add(2, 3)); // 5
import * as Utils from './04_module.mjs';

console.log(Utils.greet('Alice')); // Hi, Alice!
console.log(Utils.farewell('Alice')); // Goodbye, Alice!

클래스 (Classes)

객체 지향 프로그래밍을 지원하기 위해 클래스 문법을 도입

  • 객체의 구조와 동작을 정의
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    greet() {
        console.log(`안녕하세요, 저는 ${this.name}입니다.`);
    }
}

const person = new Person("홍길동", 30);
person.greet(); // 안녕하세요, 저는 홍길동입니다.

스프레드 연산자

배열이나 객체의 요소를 펼쳐서 복사하거나 병합할 때 사용

  • ... 연산자로 표현
// 배열 복사와 병합
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];
console.log(arr2); // [1, 2, 3, 4, 5]

// 객체 복사와 병합
const obj1 = { name: "홍길동", age: 30 };
const obj2 = { ...obj1, job: "개발자" };
console.log(obj2); // { name: "홍길동", age: 30, job: "개발자" }
  • rest parameter(나머지 값)
let obj = {
            prop0: 'p0',
            prop1: 'p1',
            prop2: 'p2'
        };
        
let [a, ...rest] = [1, 2, 3];
console.log(rest);  // [2,3]
let {prop1, ...restObj} = {prop1: 'a', prop2: 'b', prop3: 'c'};
console.log(restObj);  // {prop2: 'b', prop3: 'c'} 

구조 분해 할당

배열이나 객체의 값을 개별 변수로 쉽게 추출

  • 배열은 순서대로, 객체는 속성 이름으로 값을 할당
  • 첫 번째 주문을 별도로 처리하거나, 나머지 주문을 별도로 관리할 수 있다
// 배열 구조 분해
const [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1, 2, 3

// 객체 구조 분해
const { name, age } = { name: "홍길동", age: 25 };
console.log(name, age); // 홍길동, 25
const [firstOrder, ...remainingOrders] = newOrders;
console.log(firstOrder); // 노트북
console.log(remainingOrders); // [스마트폰, 태블릿, 모니터]

참조

java : sout-> javascript : console.log();

console.log(`문자열 ${변수명}`); 
<!-- 출력 : 문자열 변수의값 -->
<!-- ``은 문자열 내부에 변수들을 삽입할 수 있다. -->

window -> vscode 코드 실행 방법 : ctrl + alt + n

reduce()

array.reduce((누적값, 현재값) => {
    return 누적값 + 현재값;
}, 초기값);
profile
잔디 속 새싹 하나

0개의 댓글