JavaScript console: 디버깅의 첫 걸음

Jina·2025년 11월 26일

1️⃣ console이란?

console은 브라우저의 개발자 도구(DevTools)에 메시지를 출력하는 JavaScript의 내장 객체이다. 이를 통해 우리는:

  • 변수 값을 확인할 수 있고
  • 프로그램의 흐름을 추적할 수 있으며
  • 에러를 디버깅할 수 있다.

2️⃣ 자주 쓰는 console 메서드들

1. console.log() - 기본 중의 기본

// 단순 값 출력
console.log("Hello, JavaScript!");

// 여러 값을 한 번에 출력
const name = "홍길동";
const age = 25;
#### console.log("이름:", name, "나이:", age);

// 객체 출력
const user = {
  name: "홍길동",
  age: 25,
  email: "hong@example.com"
};
console.log(user);

// 배열 출력
const fruits = ["apple", "banana", "orange"];
console.log(fruits);

언제 쓸까? 변수 값을 확인하고 싶을 때, 프로그램이 특정 지점에 도달했는지 확인할 때


2. console.error() - 에러 메시지 출력

// 단순 에러 메시지
console.error("뭔가 잘못됐어요!");

// 에러 객체와 함께
try {
  throw new Error("파일을 찾을 수 없습니다.");
} catch (error) {
  console.error("에러 발생:", error.message);
}

특징: 개발자 도구에서 빨간색으로 표시되어 눈에 띈다.
언제 쓸까? 에러가 발생했음을 분명히 나타내고 싶을 때


3. console.warn() - 경고 메시지 출력

// 잘못된 입력값 경고
const age = -5;
if (age < 0) {
  console.warn("나이는 0 이상이어야 합니다. 입력된 값:", age);
}

// 더 이상 사용하지 않는 API 경고
function oldFunction() {
  console.warn("이 함수는 더 이상 사용되지 않습니다. newFunction()을 사용하세요.");
}

특징: 개발자 도구에서 노란색으로 표시된다.
언제 쓸까? 에러는 아니지만 주의가 필요할 때


4. console.table() - 데이터를 표 형태로 출력

// 배열의 객체들을 표로 출력
const users = [
  { id: 1, name: "홍길동", age: 25 },
  { id: 2, name: "김영희", age: 28 },
  { id: 3, name: "이순신", age: 30 }
];
console.table(users);

// 특정 컬럼만 출력
console.table(users, ["name", "age"]);

// 객체도 표로 출력 가능
const person = {
  name: "홍길동",
  age: 25,
  job: "개발자"
};
console.table(person);

특징: 데이터가 깔끔한 표 형태로 정렬되어 시각적으로 보기 좋다.
언제 쓸까? 복잡한 데이터 구조를 한눈에 파악하고 싶을 때


5. console.time() / console.timeEnd() - 실행 시간 측정

// 단순한 시간 측정
console.time("loop");
for (let i = 0; i < 1000000; i++) {
  // 시간이 오래 걸리는 작업
}
console.timeEnd("loop");
// 출력: loop: 12.34ms

// 여러 구간 측정
console.time("총 실행 시간");

console.time("배열 생성");
const arr = new Array(100000).fill(0);
console.timeEnd("배열 생성");

console.time("배열 정렬");
arr.sort(() => Math.random() - 0.5);
console.timeEnd("배열 정렬");

console.timeEnd("총 실행 시간");

특징: 라벨로 구분된 여러 타이머를 동시에 실행할 수 있다.
언제 쓸까? 성능 최적화를 할 때 코드 실행 시간을 비교하고 싶을 때


6. console.group() / console.groupEnd() - 메시지 그룹화

// 단순 그룹
console.group("사용자 정보");
console.log("이름: 홍길동");
console.log("나이: 25");
console.log("직업: 개발자");
console.groupEnd();

// 축약 가능한 그룹
console.groupCollapsed("상세 정보");
console.log("전화: 010-1234-5678");
console.log("이메일: hong@example.com");
console.log("주소: 서울시 강남구");
console.groupEnd();

// 중첩된 그룹
console.group("회사 정보");
console.group("개발팀");
console.log("팀원: 5명");
console.log("프로젝트: 3개");
console.groupEnd();
console.group("디자인팀");
console.log("팀원: 3명");
console.log("프로젝트: 2개");
console.groupEnd();
console.groupEnd();

특징: groupCollapsed()를 사용하면 처음에는 닫혀있는 상태로 시작한다.
언제 쓸까? 관련된 여러 메시지를 정렬해서 보고 싶을 때


7. console.assert() - 조건부 메시지 출력

// 조건이 거짓일 때만 메시지 출력
const score = 60;
console.assert(score >= 80, "점수가 80점 이상이어야 합니다. 현재 점수:", score);

// 함수의 반환값 검증
function divide(a, b) {
  console.assert(b !== 0, "0으로 나눌 수 없습니다");
  return a / b;
}

divide(10, 0); // assert 조건이 거짓이므로 메시지 출력
divide(10, 2); // 조건이 참이므로 메시지 출력 안 함

// API 응답 검증
const response = { status: 200, data: null };
console.assert(response.status === 200, "API 요청이 실패했습니다:", response);

특징: 조건을 검사하고, 거짓일 때만 메시지를 출력한다.
언제 쓸까? 특정 조건이 만족되어야 할 때 검증하고 싶을 때


8. console.trace() - 호출 스택 추적

function grandparent() {
  parent();
}

function parent() {
  child();
}

function child() {
  console.trace("호출 경로 추적");
}

grandparent();
// 출력:
// 호출 경로 추적
// child @ script.js:8
// parent @ script.js:4
// grandparent @ script.js:1

특징: 함수가 어떤 경로로 호출되었는지 알 수 있다.
언제 쓸까? 복잡한 코드에서 함수 호출 순서를 파악하고 싶을 때


3️⃣ React에서 console 활용하기

1. 컴포넌트 렌더링 추적

import { useEffect, useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("Counter 컴포넌트가 마운트되었습니다");
    
    return () => {
      console.log("Counter 컴포넌트가 언마운트되었습니다");
    };
  }, []);

  useEffect(() => {
    console.log("count가 변경되었습니다:", count);
  }, [count]);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>증가</button>
    </div>
  );
}

2. props 변화 감지

function UserCard({ userId, userName }) {
  useEffect(() => {
    console.table({ userId, userName });
  }, [userId, userName]);

  return <div>{userName}</div>;
}

3. 데이터 페치 추적

function PostList() {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    console.time("데이터 로딩");
    
    fetch("/api/posts")
      .then(res => res.json())
      .then(data => {
        console.log("받은 데이터:", data);
        console.timeEnd("데이터 로딩");
        setPosts(data);
      })
      .catch(error => {
        console.error("데이터 로딩 실패:", error);
      });
  }, []);

  return (
    <div>
      {posts.length > 0 ? (
        <ul>
          {posts.map(post => (
            <li key={post.id}>{post.title}</li>
          ))}
        </ul>
      ) : (
        <p>로딩 중...</p>
      )}
    </div>
  );
}

4. 폼 입력값 실시간 추적

function LoginForm() {
  const [form, setForm] = useState({ email: "", password: "" });

  const handleChange = (e) => {
    const { name, value } = e.target;
    const newForm = { ...form, [name]: value };
    setForm(newForm);
    console.table(newForm);
  };

  return (
    <form>
      <input
        type="email"
        name="email"
        value={form.email}
        onChange={handleChange}
        placeholder="이메일"
      />
      <input
        type="password"
        name="password"
        value={form.password}
        onChange={handleChange}
        placeholder="비밀번호"
      />
    </form>
  );
}

5. 조건부 디버깅 (개발 환경에서만 출력)

function DebugInfo() {
  useEffect(() => {
    if (process.env.NODE_ENV === "development") {
      console.group("개발 환경 정보");
      console.log("현재 환경:", process.env.NODE_ENV);
      console.log("API URL:", process.env.REACT_APP_API_URL);
      console.groupEnd();
    }
  }, []);

  return <div>앱 컴포넌트</div>;
}

4️⃣ 주의점과 팁

❌ 하지 말아야 할 것들

1. 프로덕션 환경에서 console 사용

// ❌ 나쁜 예: 프로덕션에서도 출력됨
function getUser(id) {
  const user = fetchUser(id);
  console.log("사용자 정보:", user); // 민감한 정보 노출 위험!
  return user;
}

// ✅ 좋은 예: 개발 환경에서만 출력
function getUser(id) {
  const user = fetchUser(id);
  if (process.env.NODE_ENV === "development") {
    console.log("사용자 정보:", user);
  }
  return user;
}

2. 민감한 정보 출력

// ❌ 나쁜 예: 비밀번호와 토큰 노출
const user = { email: "user@example.com", password: "secret123" };
console.log(user);

const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";
console.log("Token:", token);

// ✅ 좋은 예: 필요한 정보만 선택적으로 출력
const { email } = user;
console.log("사용자 이메일:", email);

3. 성능에 영향을 주는 과도한 console 사용

// ❌ 나쁜 예: 루프 안에서 많은 console 호출
for (let i = 0; i < 1000000; i++) {
  console.log("현재 i:", i); // 성능 저하!
}

// ✅ 좋은 예: 필요한 부분만 출력
for (let i = 0; i < 1000000; i++) {
  if (i % 100000 === 0) {
    console.log("현재 i:", i);
  }
}

4. 프로덕션 빌드에서 console 제거하지 않기

// .env.production에서
REACT_APP_DEBUG=false

// 컴포넌트에서
const debug = (message, data) => {
  if (process.env.REACT_APP_DEBUG === "true") {
    console.log(message, data);
  }
};

✅ 좋은 습관들

1. 의미 있는 라벨 사용

// ❌ 나쁜 예
console.log(userData);
console.log(count);

// ✅ 좋은 예
console.log("사용자 정보:", userData);
console.log("현재 카운트:", count);

2. 메서드를 선택적으로 사용

// 상황에 맞는 메서드 선택
console.log("일반 정보"); // 정보
console.warn("주의 필요"); // 경고
console.error("에러 발생"); // 에러
console.table(complexData); // 복잡한 데이터

3. console 디버깅을 위한 헬퍼 함수 만들기

// 재사용 가능한 디버그 함수
const logger = {
  info: (message, data) => {
    if (process.env.NODE_ENV === "development") {
      console.log(`[INFO] ${message}`, data);
    }
  },
  error: (message, error) => {
    console.error(`[ERROR] ${message}`, error);
  },
  warn: (message, data) => {
    console.warn(`[WARN] ${message}`, data);
  }
};

// 사용
logger.info("데이터 로딩 시작", { url: "/api/users" });
logger.error("요청 실패", error);

4. 브라우저 DevTools의 필터 기능 활용

// 필터링이 쉬운 접두사 사용
console.log("[UserData]", user);
console.log("[API]", response);
console.log("[State]", state);

// DevTools의 필터에 "API"라고 입력하면 [API] 메시지만 보임

🎯 정리

console의 주요 메서드:

  • console.log() - 일반 정보
  • console.error() - 에러 (빨간색)
  • console.warn() - 경고 (노란색)
  • console.table() - 데이터를 표로 표시
  • console.time() / timeEnd() - 실행 시간 측정
  • console.group() / groupEnd() - 메시지 그룹화
  • console.assert() - 조건부 출력
  • console.trace() - 호출 경로 추적

주의할 점:

  • 프로덕션 환경에서는 console 제거하기
  • 민감한 정보 출력 조심하기
  • 과도한 console 사용으로 성능 저하 방지하기

추천 방법:

  • 개발 환경과 프로덕션 환경 구분하기
  • 재사용 가능한 logger 유틸리티 만들기
  • 상황에 맞는 적절한 메서드 선택하기

console을 제대로 사용하면 버그를 빠르게 찾을 수 있고, 코드의 흐름을 쉽게 이해할 수 있다. 이제 console의 다양한 기능을 활용해서 더 효율적으로 디버깅해보자!🚀

profile
즐겁게 코딩하고 공부해요🍀

0개의 댓글