백엔드 엔지니어라도 결국 “결과물”은 브라우저 위에서 돌아갑니다.
프론트엔드까지 전문적으로 할 필요는 없지만, 최소한의 JavaScript 문법과 메서드를 알고 있으면:

  • 버그 원인 파악이 훨씬 쉬워지고

  • 프론트엔드 동료와 소통이 잘 되고

  • 간단한 화면 정도는 직접 손볼 수 있습니다.

이 글에서는 백엔드 엔지니어도 알아두면 확실히 도움이 되는 프론트엔드 자바스크립트 Best 5를 정리합니다.


1. fetch – 브라우저에서 HTTP 호출하기



왜 중요한가?

백엔드 엔지니어에게 가장 익숙한 것은 HTTP API입니다.
프론트엔드에서는 이 API를 fetch 로 호출하는 경우가 많습니다.
요청이 어떻게 보내지고, 응답/에러를 어떻게 처리하는지만 이해해도 디버깅이 크게 쉬워집니다.

기본 사용법

// GET 요청 예시
fetch('https://api.example.com/users/1')
  .then((res) => {
    if (!res.ok) throw new Error('HTTP error ' + res.status);
    return res.json(); // JSON 파싱
  })
  .then((data) => {
    console.log('user:', data);
  })
  .catch((err) => {
    console.error('fetch error:', err);
  });

POST + JSON 예시

async function createUser() {
  try {
    const res = await fetch('https://api.example.com/users', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ name: 'Alice', age: 30 }),
    });

    if (!res.ok) {
      throw new Error('HTTP error ' + res.status);
    }

    const data = await res.json();
    console.log('created:', data);
  } catch (e) {
    console.error(e);
  }
}

포인트

  • res.ok, res.status 등을 보고 서버 에러를 구분 가능

  • JSON.stringify, res.json() 사용 패턴은 거의 템플릿처럼 외워 두어도 좋음

  • CORS 에러가 나면, 브라우저 콘솔에서 fetch 요청을 어떻게 보내고 있는지 보는 습관을 들이면 좋음


2. Promiseasync/await – 비동기 로직의 기본

왜 중요한가?

프론트엔드는 대부분 비동기 입니다.

  • UI 이벤트

  • HTTP 요청

  • 타이머, WebSocket 등

이를 다루는 핵심 개념이 Promiseasync/await 입니다.
백엔드에서 비동기 I/O를 써봤다면 개념은 비슷합니다.

Promise 기본

function getUser(id) {
  return fetch(`/api/users/${id}`).then((res) => res.json());
}

getUser(1)
  .then((user) => {
    console.log(user);
  })
  .catch((err) => {
    console.error(err);
  });

async/await로 더 읽기 쉽게

async function showUser(id) {
  try {
    const res = await fetch(`/api/users/${id}`);
    if (!res.ok) throw new Error('HTTP ' + res.status);

    const user = await res.json();
    console.log(user);
  } catch (e) {
    console.error(e);
  }
}

showUser(1);

병렬 호출 (백엔드에서도 자주 쓰는 패턴)

async function loadDashboard() {
  const [userRes, statsRes] = await Promise.all([
    fetch('/api/me'),
    fetch('/api/stats'),
  ]);

  const [user, stats] = await Promise.all([
    userRes.json(),
    statsRes.json(),
  ]);

  console.log(user, stats);
}

포인트

  • Promise 기반 API는 .then().catch() 또는 async/await 둘 중 하나로 읽기 좋은 방식 선택

  • 여러 요청을 한 번에 보낼 때는 Promise.all 패턴 알아두기


3. 배열 메서드 3총사: map, filter, reduce



왜 중요한가?

프론트엔드에서도 데이터를 다룹니다.

  • 서버에서 받은 JSON 리스트를 화면용 데이터 형태로 변환

  • 특정 조건의 데이터만 필터링

  • 합계/통계를 계산

이때 배열 메서드를 많이 씁니다. 백엔드에서도 흔히 있는 컬렉션 처리와 똑같은 개념입니다.

map – 배열의 각 요소를 “변환”

const users = [
  { id: 1, name: 'Alice', age: 31 },
  { id: 2, name: 'Bob', age: 27 },
];

const names = users.map((u) => u.name);
// ['Alice', 'Bob']

filter – 조건에 맞는 것만 남기기

const adults = users.filter((u) => u.age >= 30);
// [{ id: 1, name: 'Alice', age: 31 }]

reduce – 배열을 하나의 값으로 모으기

const totalAge = users.reduce((sum, u) => sum + u.age, 0);
// 58

체이닝 예시

const avgAgeOfAdults = users
  .filter((u) => u.age >= 30)
  .reduce((acc, u, _, arr) => acc + u.age / arr.length, 0);

포인트

  • “for문만 잔뜩 있는 프론트 코드”를 보면 map/filter/reduce 로 리팩터링 포인트도 눈에 들어오기 시작

  • 백엔드(Java, Kotlin, Python, Go 등) 컬렉션 라이브러리와 대응 관계를 잡아두면 이해가 빨라짐


4. DOM 조작 핵심: querySelector, addEventListener, classList

왜 중요한가?

프레임워크(React, Vue 등)를 쓰더라도, 디버깅 단계에서는 결국 DOM을 직접 봐야 합니다.
간단한 admin 페이지나 사내 툴은 프레임워크 없이 바닐라 JS로 짜는 경우도 있습니다.

요소 선택 – querySelector

<button id="save-btn">저장</button>
const saveBtn = document.querySelector('#save-btn');

CSS 선택자 문법을 그대로 사용합니다.

  • #id

  • .class

  • button.primary

  • div > span

이벤트 핸들러 – addEventListener

saveBtn.addEventListener('click', () => {
  console.log('저장 버튼 클릭!');
});

스타일/상태 토글 – classList

<button id="save-btn" class="primary">저장</button>
saveBtn.classList.add('loading');     // 클래스 추가
saveBtn.classList.remove('primary');  // 클래스 제거
saveBtn.classList.toggle('hidden');   // 있으면 제거, 없으면 추가

이 조합만 알아도:

  • “버튼이 왜 안 눌리지?” → 실제 DOM 요소는 제대로 잡히는지, 이벤트는 걸려있는지 확인 가능

  • “이 div는 왜 안 보이지?” → classList 를 보고 어떤 상태 클래스가 적용되었는지 추적 가능

포인트

  • 프레임워크 내부 동작을 이해할 때도 DOM API 기본이 있으면 훨씬 덜 막막함

  • 브라우저 콘솔에서 직접 document.querySelector(...) 찍어보는 습관이 중요


5. ES Modules – import / export 기본

왜 중요한가?

이제 프론트엔드 JavaScript는 ES Module(ESM) 을 기본으로 사용합니다.

  • 코드가 파일 단위로 분리되고

  • 필요한 것만 import 해서 사용

  • 웹팩/바벨/번들러를 안 쓰더라도 브라우저가 직접 ESM 을 이해

백엔드(Node.js) 쪽에서도 ESM 사용이 늘고 있기 때문에, 한번 정리해두면 양쪽에 모두 도움이 됩니다.

모듈 내보내기 – export

// mathUtils.js
export function add(a, b) {
  return a + b;
}

export const PI = 3.14;

// 기본(default) export – 모듈을 대표하는 값/함수
export default function mul(a, b) {
  return a * b;
}

모듈 가져오기 – import

// main.js
import mul, { add, PI } from './mathUtils.js';

console.log(add(1, 2)); // 3
console.log(mul(3, 4)); // 12
console.log(PI);        // 3.14
  • { add, PI } : 이름 있는 export(named export) 가져오기

  • mul : default export 가져오기

브라우저에서 모듈 script 사용 예시

<script type="module" src="/static/js/main.js"></script>

이렇게 선언하면 main.js 안에서 import / export 문법을 사용할 수 있습니다.

포인트

  • 프론트/백엔드 공통으로 “모듈화” 개념은 동일

  • import 경로 규칙(./, ../, 절대경로, 번들러 별 별칭 등)을 알고 있으면 프론트 빌드 설정을 읽을 때도 덜 헷갈림


백엔드 엔지니어가 js 코드 작성하는 모습

마무리 – “프론트도 할 줄 아는 백엔드”의 최소치

정리하면, 백엔드 엔지니어가 프론트엔드 JS를 이해하기 위해 최소한으로 알아두면 좋은 것들은:

  1. fetch – 브라우저에서 HTTP 호출 및 JSON 처리

  2. Promise / async/await – 비동기 로직 구조 이해

  3. 배열 메서드(map, filter, reduce) – 데이터 변환/필터링/집계

  4. DOM 기본(querySelector, addEventListener, classList) – 화면 요소 선택, 이벤트, 상태 토글

  5. ES Modules(import / export) – 모듈 단위 코드 구조 이해

이 다섯 가지만 익숙해도:

  • 프론트엔드 코드 리뷰에 참여할 수 있고

  • 간단한 화면은 직접 구현/수정할 수 있으며

  • API 연동 이슈를 프론트/백 양쪽에서 동시에 추적할 수 있습니다.

이후에는 필요에 따라 React/Vue와 같은 프레임워크, 빌드/번들링(Webpack, Vite, SWC 등) 으로 범위를 넓혀가면 좋습니다.