반응형

Node.js 개발에서 TypeScript를 도입할 때 가장 먼저 마주치는 고민 중 하나는 바로 이것입니다.

TypeScript를 전역으로 설치할까? 로컬로 설치할까?

이 글에서는 두 방식의 차이점, 장단점, 실제 추천 시나리오까지 한번에 정리해드립니다.


✅ 전역 설치란?

전역 설치는 시스템 전체에 TypeScript를 설치하여 어느 프로젝트 디렉토리에서도 tsc 명령어를 사용할 수 있게 하는 방식입니다. 다음과 같은 명령어로 설치합니다:

npm install -g typescript

설치 후에는 터미널 어디에서나 다음 명령이 작동합니다:

tsc --version
tsc yourfile.ts

전역 설치의 장점

  • tsc 명령을 터미널 어디서든 바로 쓸 수 있다
  • CLI 툴 사용 시 빠르게 실행 가능
  • 전역 설정에 익숙한 개발자에게 편리

전역 설치의 단점

  • 버전 충돌 가능성: 프로젝트마다 TypeScript 버전이 다를 경우 문제 발생
  • 팀 협업에서 위험: 다른 개발자의 시스템에 같은 버전이 설치되어 있다고 보장할 수 없음
  • CI/CD 파이프라인에서 재현 불가

✅ 로컬 설치란?

로컬 설치는 해당 프로젝트 폴더 안에 TypeScript를 설치하는 방식입니다. 보통 개발 의존성으로 추가합니다:

npm install --save-dev typescript

설치 후에는 전역 명령 대신 npx를 사용해 실행합니다:

npx tsc
npx tsc --init

로컬 설치의 장점

  • 프로젝트별로 TypeScript 버전을 고정할 수 있어 안정성 확보
  • 모든 팀원이 동일한 환경에서 작업 가능
  • CI/CD 환경에서도 100% 재현 가능
  • package.json만 보면 어떤 버전이 쓰였는지 알 수 있다

로컬 설치의 단점

  • tsc를 직접 실행하려면 npx 또는 경로를 지정해야 한다
  • 여러 프로젝트를 오가며 전역 설치처럼 쓰고 싶으면 약간 번거로움

🔍 어떤 상황에 어떤 설치를 써야 할까?

  • 혼자 실습하거나 빠르게 테스트하는 경우
    전역 설치도 무방합니다.
  • 팀 프로젝트, 버전 관리, 협업, CI/CD 구성이 필요한 경우
    반드시 로컬 설치가 권장됩니다.

요즘 대부분의 실제 프로젝트는 typescript를 로컬로 설치하고 npx tsc 또는 tsc npm script로 실행합니다.


🧙 마무리

전역 설치는 빠르고 편리하지만, 협업과 재현성을 위해서는 로컬 설치가 훨씬 안전하고 추천되는 방식입니다.

최종적으로는 다음과 같은 전략을 추천합니다:

  • CLI 툴 실습이나 글로벌 테스트용 → 전역 설치
  • 실제 서비스, 팀 프로젝트, 오픈소스, CI/CD → 로컬 설치 (with --save-dev)

🎯 참고 명령어 요약

# 전역 설치
npm install -g typescript

# 로컬 설치
npm install --save-dev typescript

# 로컬 실행
npx tsc

 

728x90
반응형
반응형

🔍 ??란?

??는 null 병합 연산자 (Nullish Coalescing Operator) 입니다.
JavaScript(ES2020)부터 도입된 문법으로, 값이 null 또는 undefined일 때 대체값(default value) 을 설정하는 데 사용됩니다.

const result = value ?? defaultValue;

📘 동작 방식

왼쪽 값 ?? 결과
null 오른쪽 값 반환
undefined 오른쪽 값 반환
나머지 값들 (0, '', false) 왼쪽 값 그대로 사용
let name = null ?? "익명";       // "익명"
let age = undefined ?? 30;       // 30
let isActive = false ?? true;    // false ← 주의!
let count = 0 ?? 10;             // 0 ← 주의!

✅ false, 0, "" 는 null이 아님! → ??는 무시하고 그대로 반환


🔁 || (OR 연산자)와 차이점?

||는 falsy 값 전체를 체크

let title = "" || "기본 제목";  // "기본 제목"

??는 null / undefined 만 체크

let title = "" ?? "기본 제목";  // ""​
표현식 결과 이유
`null   '기본'`
`0   100`
0 ?? 100 0 null/undefined 아니므로 유지

결론:

  • ||는 많이 비우고 싶을 때
  • ??는 정말 null/undefined일 때만 대체하고 싶을 때 사용하세요.

🧱 실전 예시

✅ 환경 변수 기본값 설정

const PORT = process.env.PORT ?? 3000;

→ PORT가 설정되지 않았을 때만 기본값 3000 사용


✅ 사용자 입력 처리

function getUserName(user) {
  return user.name ?? "손님";
}

→ user.name이 null 또는 undefined일 때만 "손님" 반환


✅ 객체 병합

const defaultOptions = {
  retry: 3,
  timeout: 5000
};

const userOptions = {
  timeout: null
};

const config = {
  retry: userOptions.retry ?? defaultOptions.retry,
  timeout: userOptions.timeout ?? defaultOptions.timeout
};

console.log(config); // { retry: 3, timeout: 5000 }

→ timeout: null은 무시하고 default 사용


❌ 에러 주의: 옵셔널 체이닝과 혼용 시

let username = user?.info?.name ?? "익명";
  • user 또는 info가 없으면 undefined
  • ??로 "익명" 설정됨 → 매우 강력한 조합
728x90
반응형
반응형

기본적으로 new Date()는 UTC 기준으로 동작합니다. 이를 **KST(한국 표준시, UTC+9)**로 변환하는 방법을 설명합니다.

🚀 1. Intl.DateTimeFormat 사용 (권장)

JavaScript의 Intl.DateTimeFormat API를 사용하면 타임존 변환이 간단합니다.

const date = new Date();

const kstDate = new Intl.DateTimeFormat('ko-KR', {
  timeZone: 'Asia/Seoul',  // ✅ KST 적용
  year: 'numeric',
  month: '2-digit',
  day: '2-digit',
  hour: '2-digit',
  minute: '2-digit',
  second: '2-digit',
  hour12: false, // ✅ 24시간제 사용
}).format(date);

console.log(`📌 KST 시간: ${kstDate}`);

 

💡 출력 예시:

📌 KST 시간: 2024. 02. 25. 15:30:45

Intl.DateTimeFormat을 사용하는 이유

  • 최신 표준 지원 (ECMAScript 국제화)
  • 시간대 자동 적용
  • 성능 최적화

 

🚀 2. toLocaleString() 사용

toLocaleString()을 사용하여 KST로 변환할 수도 있습니다.

const date = new Date();
const kstDate = date.toLocaleString('ko-KR', { timeZone: 'Asia/Seoul' });

console.log(`📌 KST 시간: ${kstDate}`);

💡 출력 예시:

📌 KST 시간: 2024. 2. 25. 오후 3:30:45

✅ toLocaleString()은 간편하지만, 시간 형식이 다소 달라질 수 있음.

 

 

🚀 3. moment-timezone 사용 (강력한 기능 제공)

moment-timezone을 사용하면 더 다양한 포맷 지정 가능.

📌 설치

npm install moment-timezone

📌 코드 예제

const moment = require('moment-timezone');

const kstDate = moment().tz("Asia/Seoul").format("YYYY-MM-DD HH:mm:ss");

console.log(`📌 KST 시간: ${kstDate}`);

💡 출력 예시:

📌 KST 시간: 2024-02-25 15:30:45

moment-timezone 사용 시 장점

  • 여러 타임존 변환 가능
  • 포맷 지정 가능
  • Date 객체와 연동 가능

 

🚀 4. Date 객체에서 직접 변환 (UTC 오프셋 적용)

UTC 시간에 9시간을 추가하여 KST로 변환할 수도 있습니다.

const date = new Date();
const kstDate = new Date(date.getTime() + (9 * 60 * 60 * 1000)); // ✅ UTC+9 적용

console.log(`📌 KST 시간: ${kstDate.toISOString().replace('T', ' ').slice(0, 19)}`);

💡 출력 예시:

📌 KST 시간: 2024-02-25 15:30:45

✅ 직접 Date 객체를 변환하는 방법이지만, Intl.DateTimeFormat보다 추천하지 않음.

 

 

🎯 정리 (어떤 방법을 선택할까?)

방법코드 예제장점단점
Intl.DateTimeFormat ✅ new Intl.DateTimeFormat('ko-KR', { timeZone: 'Asia/Seoul' }) 표준 지원, 성능 최적화 포맷 지정이 다소 제한적
toLocaleString() ✅ date.toLocaleString('ko-KR', { timeZone: 'Asia/Seoul' }) 간편 사용 출력 형식이 다를 수 있음
moment-timezone ✅ moment().tz("Asia/Seoul").format("YYYY-MM-DD HH:mm:ss") 강력한 포맷팅 기능 패키지 설치 필요
UTC 오프셋 변환 ✅ new Date(date.getTime() + (9 * 60 * 60 * 1000)) 직접 변환 가능 DST(일광 절약 시간) 고려 안됨

📌 추천 방법

  • 최신 프로젝트 & 표준 지원이 필요하면 → Intl.DateTimeFormat()
  • 간단하게 변환하려면 → toLocaleString()
  • 강력한 포맷팅이 필요하면 → moment-timezone
  • UTC에서 오프셋 변환하려면 → Date + 9시간 추가
728x90
반응형
반응형

Vue.js를 개발할 때 yarn run dev 또는 npm run dev 명령어를 실행하면, 로컬에서 개발 서버가 실행됩니다. 하지만 실수로 Control + Z (^Z)를 눌러 suspended(정지됨) 상태가 되면, 터미널에서 다시 실행하거나 정상적으로 종료하는 방법이 필요합니다.

이 글에서는 Mac에서 Vue.js 개발 서버가 Suspended 상태가 되었을 때 해결하는 4가지 방법을 소개합니다.


✅ Suspended 상태란?

Suspended(정지됨) 상태란?
터미널에서 yarn run dev 실행 중 Control + Z 키를 눌렀을 때, 실행 중이던 프로세스가 중지(Suspended)되고 백그라운드로 이동하는 상태를 말합니다.

이 상태에서는 서버가 멈춘 것처럼 보이지만, 여전히 프로세스가 살아있습니다. 이를 해결하기 위해 다시 실행하거나 종료하는 방법을 알아보겠습니다.


🔥 해결 방법 1: fg를 사용해 다시 실행 후 종료

1.1 정지된 프로세스를 다시 실행

터미널에서 아래 명령어를 입력하면, 중지된 프로세스를 다시 실행할 수 있습니다.

fg

이후 Control + C (^C)를 눌러 정상 종료합니다.

📝 설명:
fg(foreground) 명령어는 suspended 상태에서 프로세스를 다시 실행합니다.


🔥 해결 방법 2: 백그라운드 실행 후 종료

2.1 정지된 프로세스를 백그라운드에서 실행

bg

이 명령어를 입력하면, 중지된 프로세스가 백그라운드에서 실행됩니다.

2.2 실행 중인 백그라운드 작업 확인

jobs -l

이 명령어를 입력하면, 백그라운드에서 실행 중인 프로세스 목록이 표시됩니다.

[1]  +  12345 Suspended   yarn run dev

위에서 12345는 프로세스 ID(PID)입니다.

2.3 특정 프로세스 종료

kill 12345

또는 아래 명령어를 사용해 백그라운드 프로세스를 종료할 수도 있습니다.

kill %1

📝 설명:
%1은 jobs 명령어에서 [1]로 표시된 백그라운드 작업의 번호입니다.


🔥 해결 방법 3: 강제 종료 (kill -9 사용)

만약 fg 또는 kill로도 프로세스가 종료되지 않는다면, 강제로 종료하는 방법이 있습니다.

3.1 실행 중인 프로세스 ID(PID) 찾기

ps aux | grep yarn

이 명령어를 실행하면 실행 중인 yarn run dev의 프로세스 ID(PID)를 찾을 수 있습니다.

user     12345   0.0  0.1  2458908  8000 s001  S+   10:34AM   0:02.34 node /path/to/yarn run dev

위에서 12345가 프로세스 ID입니다.

3.2 해당 PID를 강제 종료

kill -9 12345

📝 설명:
kill -9는 강제 종료 명령어로, 해당 프로세스를 즉시 중단시킵니다.


🔥 해결 방법 4: 터미널을 닫고 새로 열기

만약 위 방법으로도 해결되지 않는다면, 가장 간단한 방법은 터미널을 닫고 다시 여는 것입니다.

  1. 현재 실행 중인 터미널을 닫습니다.
  2. 새 터미널을 열고 다시 yarn run dev를 실행합니다.

이 방법을 사용하면, 기존에 중지된 프로세스가 자동으로 종료되면서 새로운 프로세스로 실행됩니다.


🚀 최종 정리: 어떤 방법을 선택할까?

해결 방법명령어추천 상황

Suspended 상태에서 다시 실행 후 종료 fg → Control + C 가장 일반적인 해결책
백그라운드에서 실행 후 종료 bg → jobs -l → kill %1 여러 개의 프로세스가 있을 때
프로세스 ID로 강제 종료 `ps aux grep yarn→kill -9 <PID>`
터미널 닫고 재시작 터미널 종료 후 다시 실행 모든 방법이 안될 때

💡 가장 추천하는 방법:

  • fg로 복구한 후 Control + C로 종료하는 것이 가장 빠르고 안정적인 해결책입니다.
  • 하지만 프로세스가 종료되지 않는다면 kill -9 <PID>를 사용하세요.

이제 Vue.js 개발 서버가 suspended 상태에 빠졌을 때 당황하지 말고, 위 방법을 활용하여 빠르게 해결해보세요! 🚀

 

#VueJS #MacOS #TerminalCommands #Debugging #DevTips #FrontendDev #WebDevelopment #JavaScript

728x90
반응형
반응형

fs.createReadStream + csv-parser 사용 시 비동기 처리에 주의하세요!


📌 문제 상황: 비동기 스트림에서 예상치 못한 동작

CSV 파일을 읽고, 특정 수량(quantity)만큼 데이터를 처리하려고 했지만, 모든 데이터가 처리됨. 😲

목표:

  • CSV 데이터에서 특정 개수(quantity)만 읽고 중단
  • 비동기 함수(await)가 정확히 작동하도록 수정

💥 문제 발생 코드: 비동기 흐름 제어 실패

import fs from 'fs';
import csv from 'csv-parser';

let count = 0;
const quantity = 20;
const winDataList: any[] = [];

fs.createReadStream(filePath)
  .pipe(csv())
  .on("data", async (data: CsvRow) => {
    if (count < quantity) {
      const email = data.email;
      const point = data.point;
      const choice = data.choice;
      const choiceImage = { a: "imagea", b: "imageb" }[choice]!;

      winDataList.push({ email, point, choice, choiceImage });
      console.log("Processing:", email, point);

      await updateEmailFile(email, fileName); // 비동기 작업
      await updateEmail(email);              // 비동기 작업

      count++;
    } else {
      return; // ❌ 스트림은 계속 실행됨
    }
  });

⚠️ 문제 원인:

  1. csv-parser는 비동기 흐름을 기다리지 않음.
  2. await 사용했지만, 스트림은 비동기 작업과 무관하게 계속 실행.
  3. 결과: 모든 CSV 데이터가 처리됨. 😱

해결 방법: 스트림 흐름을 명확히 제어

### 🎯 방법 1: stream.destroy()로 스트림 종료

count가 quantity에 도달하면 스트림 자체를 종료하여 추가 데이터를 읽지 않도록 합니다.

import fs from 'fs';
import csv from 'csv-parser';

let count = 0;
const quantity = 20;
const winDataList: any[] = [];

const stream = fs.createReadStream(filePath)
  .pipe(csv());

stream.on("data", async (data: CsvRow) => {
  if (count < quantity) {
    const email = data.email;
    const point = data.point;
    const choice = data.choice;
    const choiceImage = { a: "imagea", b: "imageb" }[choice]!;

    winDataList.push({ email, point, choice, choiceImage });
    console.log("Processing:", email, point);

    await updateEmailFile(email, fileName);
    await updateEmail(email);

    count++;

    if (count >= quantity) {
      stream.destroy(); // ✅ 스트림 완전 종료
    }
  }
});

stream.on("close", () => {
  console.log("Stream closed after processing", count, "items.");
});

stream.on("error", (err) => {
  console.error("Stream error:", err);
});

💡 장점:

  • 간단하고 빠른 구현
  • quantity에 도달하면 즉시 스트림 종료

단점:

  • 스트림 완전 종료: 이후 데이터는 절대 다시 읽을 수 없음

### 🎯 방법 2: pause() & resume()으로 정교한 제어

각 데이터 처리 시 스트림을 일시정지하고, 비동기 작업 완료 후 다시 재개합니다.

import fs from 'fs';
import csv from 'csv-parser';

let count = 0;
const quantity = 20;
const winDataList: any[] = [];

const stream = fs.createReadStream(filePath)
  .pipe(csv());

stream.on("data", async (data: CsvRow) => {
  if (count < quantity) {
    stream.pause(); // ✅ 데이터 흐름 일시 정지

    const email = data.email;
    const point = data.point;
    const choice = data.choice;
    const choiceImage = { a: "imagea", b: "imageb" }[choice]!;

    winDataList.push({ email, point, choice, choiceImage });
    console.log("Processing:", email, point);

    await updateEmailFile(email, fileName);
    await updateEmail(email);

    count++;

    if (count >= quantity) {
      stream.destroy(); // ✅ 최대 수량 도달 시 스트림 종료
    } else {
      stream.resume(); // ✅ 다음 데이터 읽기 재개
    }
  }
});

stream.on("close", () => {
  console.log("Stream closed after processing", count, "items.");
});

stream.on("error", (err) => {
  console.error("Stream error:", err);
});

💡 장점:

  • 비동기 흐름 제어 가능 (데이터 순서 보장)
  • 중간에 작업 재개 가능

단점:

  • 코드 복잡성 증가

🎯 방법 3: pipeline()으로 스트림 관리 최적화

Node.js 10+에서는 **stream.pipeline()**을 사용해 에러 핸들링비동기 흐름 관리를 더 효율적으로 처리할 수 있습니다.

import { createReadStream } from 'fs';
import { pipeline } from 'stream';
import csv from 'csv-parser';
import { promisify } from 'util';

const asyncPipeline = promisify(pipeline);

async function processCSV(filePath: string, quantity: number) {
  let count = 0;
  const winDataList: any[] = [];

  await asyncPipeline(
    createReadStream(filePath),
    csv(),
    async function* (source) {
      for await (const data of source) {
        if (count >= quantity) break;

        const email = data.email;
        const point = data.point;
        const choice = data.choice;
        const choiceImage = { a: "imagea", b: "imageb" }[choice]!;

        winDataList.push({ email, point, choice, choiceImage });
        console.log("Processing:", email, point);

        await updateEmailFile(email, fileName);
        await updateEmail(email);

        count++;
      }
    }
  );

  console.log("Processed", count, "records");
}

processCSV(filePath, 20).catch(console.error);

💡 장점:

  • 에러 핸들링 포함
  • 비동기 흐름 자연스럽게 제어 가능
  • 중간에 멈추거나 재시작 가능

단점:

  • Node.js 10+ 필요
  • 복잡한 로직에는 적합하지 않을 수 있음

결론: 어떤 방법을 선택할까?

방법장점단점추천 상황

stream.destroy() 빠르고 단순 이후 데이터 다시 읽기 불가 간단한 데이터 처리
pause() & resume() 비동기 흐름 제어, 순서 보장 코드 복잡성 증가 정교한 흐름 제어 필요 시
pipeline() 에러 핸들링, 비동기 흐름 최적화 Node.js 10+ 필요 대규모 스트림 작업

📊 💡 최종 추천

  • 빠르게 끝내야 한다면 → destroy()
  • 비동기 흐름을 제어하고 싶다면 → pause() & resume()
  • 에러 핸들링과 확장성을 고려한다면 → pipeline()

💬 마무리

Node.js의 스트림은 효율적인 데이터 처리를 가능하게 하지만, 비동기 흐름 관리에 유의해야 합니다. 특히 대용량 CSV 처리에서는 pause()와 destroy()를 적절히 사용하여 메모리 사용을 줄이고, 필요 시 pipeline()으로 에러 핸들링까지 고려하세요. 🚀

 

#NodeJS #JavaScript #CSVParsing #StreamAPI #AsyncProgramming #DataProcessing #BackendDevelopment #NodeJSTips #FullStackDevelopment #WebDevelopment #Asynchronous #CodingTips #DeveloperLife #CodeOptimization #ErrorHandling #NodeJSTutorial #BackendEngineer #ProgrammingTips #SoftwareEngineering #TechBlog

💡 활용 팁:

  • 기술 태그 (#NodeJS, #JavaScript, #StreamAPI) → 개발자 타겟팅
  • 문제 해결 태그 (#ErrorHandling, #CodeOptimization) → 검색 최적화
  • 커뮤니티 태그 (#DeveloperLife, #TechBlog) → 더 넓은 도달범위 확보
728x90
반응형
반응형

JavaScript를 포함한 대부분의 프로그래밍 언어는 IEEE 754 표준에 따른 이중 정밀도 부동소수점(floating point) 방식을 사용합니다. 이 방식은 실수를 이진수로 표현하는데, 모든 소수를 정확하게 표현할 수 없기 때문에 내부적으로 약간의 오차가 발생합니다.

예를 들어, 아래와 같이 0.2와 0.4를 더하면:

const result = 0.2 + 0.4;
console.log(result); // 0.6000000000000001

 

왜 정확히 0.6이 나오지 않을까요? 그 이유는 0.2와 0.4를 이진수로 표현할 때 무한소수로 나타나기 때문에 반올림 과정에서 미세한 오차가 누적되기 때문입니다.

부동소수점 오차의 원인

IEEE 754 표준에서는 모든 숫자를 2진법으로 표현합니다. 그러나 10진법의 소수 중에는 2진법으로 정확하게 표현할 수 없는 수들이 있습니다. 예를 들어,

  • 0.2는 2진수로 근사치로 표현되고,
  • 0.4 역시 근사치로 표현됩니다.

이러한 근사치 계산 과정에서 오차가 발생하고, 두 값을 더할 때 오차가 누적되어 예상치 못한 결과가 나오게 됩니다.

해결 방법

부동소수점 연산 오차 문제를 완화하기 위한 몇 가지 방법을 소개합니다.

1. 반올림 사용하기

연산 결과를 원하는 소수점 자리수로 반올림하는 방법입니다. Number.prototype.toFixed() 메서드를 사용하면 문자열로 반환되므로, 이를 Number() 함수를 통해 숫자형으로 변환할 수 있습니다.

const result = 0.2 + 0.4;
const rounded = Number(result.toFixed(2)); // 소수점 둘째 자리까지 반올림
console.log(rounded); // 0.6

이 방법은 결과 값을 표현할 때는 유용하지만, 연산 자체의 정확도를 높이는 방법은 아닙니다.

2. 정수 연산 후 나누기

실수를 직접 계산하는 대신 정수 연산을 한 후 최종 결과를 원하는 단위로 변환하는 방법입니다.

const result = (2 + 4) / 10;
console.log(result); // 0.6

이 방법은 소수점 이하의 연산을 정수로 처리하여 부동소수점 오차를 피할 수 있는 장점이 있습니다. 그러나 모든 경우에 적용하기는 어려울 수 있습니다.

3. 수학 라이브러리 사용하기

보다 정밀한 계산이 필요하거나 부동소수점 오차를 완전히 제어하고 싶다면, Decimal.jsBig.js와 같은 라이브러리를 사용하는 것이 좋습니다.

Big.js 예제:

const Big = require('big.js');

const result = Big(0.2).plus(Big(0.4));
console.log(result.toString()); // "0.6"

// 결과를 number 타입으로 변환하려면:
const numberResult = Number(result);
console.log(numberResult); // 0.6

이 방법은 라이브러리 내부에서 소수 연산의 오차를 보완하는 알고리즘을 사용하므로, 보다 신뢰할 수 있는 결과를 제공합니다.


결론

JavaScript의 부동소수점 연산은 IEEE 754 표준에 의해 발생하는 오차 때문에, 0.2 + 0.4의 결과가 0.6000000000000001로 나타납니다. 이러한 문제를 해결하기 위해서는:

  1. 반올림을 통해 원하는 자리수로 결과를 조정하거나,
  2. 정수 연산 후 나누기 방식을 사용하거나,
  3. Decimal.js, Big.js와 같은 수학 라이브러리를 활용하여 보다 정밀한 계산을 수행하는 방법이 있습니다.

상황에 따라 적절한 방법을 선택하여 부동소수점 연산 오차 문제를 완화할 수 있습니다.

 

 

728x90
반응형
반응형

JavaScript의 옵셔널 체이닝(Optional Chaining) 연산자 ?.는 객체의 속성에 접근할 때, 해당 속성이 존재하지 않더라도 에러를 발생시키지 않고 undefined를 반환하는 유용한 문법입니다. 이는 깊게 중첩된 객체 구조에서 속성에 접근할 때 특히 유용하며, 코드의 가독성과 안전성을 크게 향상시켜줍니다.

왜 옵셔널 체이닝이 필요한가?

객체의 속성에 접근할 때, 종종 해당 속성이 존재하지 않을 가능성을 고려해야 합니다. 예를 들어, 서버로부터 받은 데이터가 항상 동일한 구조를 가지지 않거나, 어떤 필드가 조건에 따라 존재하지 않을 수 있습니다. 이러한 상황에서 안전하게 속성에 접근하기 위해서는 많은 방어적 코드를 작성해야 합니다.

let person = {}; // person 객체는 비어있습니다.

console.log(person.contactInfo.address); // TypeError: Cannot read property 'address' of undefined

 

위의 코드에서 user.address가 undefined이기 때문에 user.address.street에 접근하려고 하면 오류가 발생합니다. 이 문제를 해결하기 위해 보통 아래와 같은 방어적 코드를 작성합니다.

let person = {};

if (person && person.contactInfo && person.contactInfo.address) {
  console.log(person.contactInfo.address);
} else {
  console.log('주소가 없습니다.');
}

 

하지만 이러한 방어적 코드는 가독성을 떨어뜨리고 작성하기 번거로울 수 있습니다. 이를 해결하기 위해 등장한 것이 옵셔널 체이닝 연산자입니다.

옵셔널 체이닝의 사용법

옵셔널 체이닝 연산자를 사용하면 중첩된 객체의 속성에 안전하게 접근할 수 있습니다. 옵셔널 체이닝은 ?. 형태로 사용되며, 해당 속성이 존재하지 않을 경우 undefined를 반환합니다.

let person = {}; // person 객체는 여전히 비어있습니다.

console.log(person?.contactInfo?.address); // undefined

 

위의 코드에서 user.address가 undefined이더라도 오류가 발생하지 않고 undefined를 반환합니다.

옵셔널 체이닝의 다양한 사용 예

1. 객체 속성 접근

let person = {
  fullName: 'John Doe',
  contactInfo: {
    address: '456 Elm St'
  }
};

console.log(person?.contactInfo?.address); // '456 Elm St'
console.log(person?.employment?.position); // undefined

 

2. 함수 호출

옵셔널 체이닝은 함수 호출에도 사용할 수 있습니다. 함수가 존재하지 않을 경우 undefined를 반환합니다.

let person = {
  sayHello: function() {
    console.log('Hi there!');
  }
};

person.sayHello?.(); // 'Hi there!'
person.sayGoodbye?.(); // 아무 일도 일어나지 않음

 

3. 배열 요소 접근

옵셔널 체이닝은 배열의 요소 접근에도 사용할 수 있습니다.

let employees = [{ fullName: 'John Doe' }, { fullName: 'Jane Smith' }];

console.log(employees[0]?.fullName); // 'John Doe'
console.log(employees[3]?.fullName); // undefined

 

결론

옵셔널 체이닝 연산자는 객체의 속성에 안전하게 접근할 수 있게 해주는 강력한 도구입니다. 이를 통해 코드의 가독성을 높이고, 중첩된 객체 구조를 다룰 때 발생할 수 있는 오류를 예방할 수 있습니다. JavaScript 코드에서 옵셔널 체이닝을 적절히 활용하면 보다 안정적이고 유지보수하기 쉬운 코드를 작성할 수 있습니다.

728x90
반응형

+ Recent posts