자세히 보기

Matthew Tyson
Contributing Writer

자바스크립트 개발자가 자주 찾는 10가지 문제와 해결법

어느 주제에 관해 자주 묻는 질문을 목록으로 만든 것을 FAQ(Frequently Asked Questions)라고 한다. 이 개념을 조금 변형한 FSS(Frequently Sought Solutions)는 자주 도움을 요청하는 문제에 대한 해결 방법을 정리한 목록이다. FSS는 '초보자용' 질문을 넘어 프로그래머를 괴롭히는 실질적인 문제를 다룬다.

여기서는 자바스크립트에서 개발자가 반복적으로 직면하는 10가지 문제와 이를 해결하는 데 도움이 되는 간단한 팁과 코드 샘플을 소개한다.

1. 배열 다루기

프로그래머가 항상 해야 하는 일 중 하나는 데이터 배열 조작이다. 이 데이터는 객체일 수도 있고, 숫자, 문자열일 수도 있다. 다양한 곳에서 가져온 이 데이터를 정렬하고 정리하고 더 작은 조각으로 나누는 등 온갖 종류의 작업을 한다.

고전적인 명령형 루프를 포함해서 배열로 필요한 작업을 수행하는 방법은 많다. 여기에는 정답이 없다. 그러나 현대 자바스크립트는 간결하고 능률적으로 작업을 수행할 수 있게 해주는 매우 유용한 함수 연산 모음을 제공한다. 기억하고 있다가 적절한 시점에서 어느 함수 연산을 사용해야 하는지만 알면 된다.

다음 배열을 보자.

const products = [
  { id: 1, name: “Apple”, price: 1.99, inStock: true },
  { id: 2, name: “Banana”, price: 0.79, inStock: false },
  { id: 3, name: “Orange”, price: 2.49, inStock: true },
];
 
재고가 있는 제품만 필터링해서 가격을 기준으로 오름차순 정렬하려면 이렇게 하면 된다.

const availableProducts = products.filter(product => product.inStock)
.sort((a, b) => a.price – b.price);

availableProducts에는 inStock이 true인 항목만 저장되며 목록은 가격을 기준으로 정렬된다. filter와 sort 메소드는 모두 기본 내장된 메소드이며 함수를 인수로 받는다. 이를 “고차 함수”라고 한다. 함수형 프로그래밍의 대표적인 특징이다.

각 함수 인수는 연산할 요소를 취한 다음 이를 기반으로 작업을 수행한다. filter의 경우 함수가 true를 반환하면 결과 배열에 요소가 유지된다. sort()에서는 알고리즘이 배열을 거칠 때 두 개의 인수가 제공된다. 결과가 음수이면 첫 번째 항목이 먼저 정렬되고 반대면 반대로 정렬된다(0이 반환되면 등가).

자바스크립트 배열에 대해 더 알아보기
자바스크립트 배열을 사용한 함수형 프로그래밍‘에서 이와 같은 유용한 툴을 더 많이 볼 수 있다.


2. DOM 조작

사용자 인터페이스를 나타내며 이를 변경할 수 있게 해주는 DOM(문서 객체 모델)을 다루는 작업에는 리액티브 프레임워크가 사용되는 경우가 많지만, 개발자는 여전히 자바스크립트를 사용해서 DOM과 직접 상호작용해야 한다.

DOM 조작은 두 가지 기본 요소로 축약된다. 이벤트에 반응하기와 요소 및 속성 변경하기다. 다음 예제를 보자.

 
<!DOCTYPE html>
<html>
<body>
  <h1 id=”heading”>Welcome to our website!</h1>
  <button id=”change-button”>Change Heading</button>

  <script>
    const changeButton = document.getElementById(“change-button”); 
    changeButton.addEventListener(“click”, function(event) { 
      const clickedElement = event.target;  
      clickedElement.style.color = “red”; 
      const heading = document.getElementById(“heading”); 
      heading.textContent = “This heading has been changed!”;
    });
  </script>
</body>
</html>
 
제목(h1)과 버튼(button)이 있는 간단한 HTML 페이지다. 이 페이지가 만드는 DOM 트리에서 <h1>과 <button> 요소는 <body> 안에 중첩된다. 또한 일부 자바스크립트를 실행하는 <script> 태그도 있다.

자바스크립트는 document.getElementById(“change-button”) 함수를 사용해 ID별로 버튼 요소를 가져온다.

버튼에서는 addEventListener를 사용해 이벤트 리스너를 설정한다. 이는 페이지에 반응성을 추가하기 위한 기본적인 메커니즘이다. 이벤트 유형은 많다. 예제에서는 “click”을 사용해서 버튼 클릭에 반응한다. 두 번째 인수는 콜백 함수를 제공할 수 있게 해준다.

콜백 함수는 event라는 이름의 인수 하나를 받는다. 사용할 수 있는 여러 속성이 있지만 주로 사용할 것은 target이다. 이 속성에는 클릭된 요소가 저장된다. 이를 사용하여 버튼 스타일 색을 빨간색으로 바꾼다.

마지막으로, ID로 h1 헤당 요소를 가져와서 텍스트를 변경한다. 텍스트와 색 변경은 DOM 요소 속성 사용의 예제다.


3. 비동기 프로그래밍

현대 자비스크립트는 비동기 프로그래밍에 효과적이다. 비동기 프로그래밍을 해야 할 일이 많으므로 중요한 장점이다. 비동기 프로그래밍을 위한 세 가지 주 메커니즘은 콜백, 프로미스, async/await이다.

콜백은 전통적이다.

let myCallback = function(){
  console.log(“I was called after one second.”);
}

setTimeout(myCallback, 1000);
 
이는 myCallback 함수를 비동기적으로 실행할 수 있게 해준다(여기서는 1,000밀리초 후에). Promise를 사용해서 같은 작업을 수행하는 방법은 다음과 같다.

function waitOneSecond() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(“I was called after one second.”);
    }, 1000);
  });
}

waitOneSecond()
  .then(message => console.log(message))
.catch(error => console.error(error));
 
여전히 비동기 연산, 그리고 사실상 비동기 콜백이 이뤄지지만 여기서는 Promise 안에 래핑된다. 따라서 중첩 콜백 없이 then과 catch 메소드를 호출해서 결과를 처리할 수 있다. 

자바스크립트 프로미스에 대해 더 알아보기
프로미스에 대한 더 자세한 내용은 ‘자바스크립트 ‘프로미스’ 실전 사용법 5가지‘에서 볼 수 있다.

async/await 블록은 프로미스를 더 간소하고 선언적으로 만들어준다. 다음과 같이 프로미스를 사용하기 위한 코드를 작성할 수 있다.

async function waitOneSecondAsync() {
  try {
    new Promise(resolve => setTimeout(() => console.log(“I was called after one second.”), 1000));
  } catch (error) {
    console.error(error);
  }
}
 
console.log(“Before”);
await waitOneSecondAsync();
console.log(“after”);
 
이 코드에서 await을 없애면 “before”와 “after” 로그 출력이 시간 만료 전에 일어난다. await은 async 연산이 완료될 때가지 멈출 수 있게 해준다. Promise를 then()과 함께 사용하는 것과 비슷하다.

비동기 프로그래밍에 대해 더 알아보기
자바스크립트의 비동기 프로그래밍에 대한 더 자세한 내용은 ‘자바스크립트 콜백, 프로미스, async/await 설명‘에서 볼 수 있다.


4. 오류 처리

코드는 언제든 예외를 발생시켜(오류 던지기라고도 함) 문제를 나타낼 수 있다.

throw new Error(“Something is not right here.”)
 
이렇게 하면 정상적인 실행 흐름이 중단되고 호출 스택이 “풀린다(unwind)”. 스택에 try/catch 블록이 포함되는 경우 처음 만난 블록이 오류를 처리한다. 간단한 예제를 보면 다음과 같다.

 
try{ 
  throw new Error(“Something is not right here.”) 
} catch(e) { 
  console.log(“Got an error: ” + e);
}
 
이 코드는 ‘Got an error: Error: Something is not right here.’를 출력한다.

복구, 재시도, 기타 상황에 따른 전략 등 더 정교한 오류 처리도 가능하다. 오류가 있는지 여부에 따라 호출되는 finally 블록도 정의할 수 있다.

try{ 
  throw new Error(“Something is not right here.”) 
} catch(e) { 
  console.log(“Got an error: ” + e);
} finally {
  console.log(“No matter what, I’ll print.”);
}

비동기 연산을 프로미스와 함께 사용할 때 catch()와 finally()를 비슷한 방식으로 사용할 수 있다. 시간 만료 예제로 계속 진행해 보자.

function waitOneSecond() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error(“Network error!”));  
    }, 1000);
  });
}

waitOneSecond()
  .then(message => console.log(message))  
.catch(error => console.error(“Error:”, error.message))   .finally(() => console.log(“This always executes, regardless of errors.”));  
 
여기서는 오류가 항상 던져지므로 catch()와 finally() 블록은 항상 실행된다. 실제 코드에서는 정상적인 실행이 오류를 던지지 않을 경우 catch 호출도 일어나지 않는다.


5. 객체 시작하기

객체는 자바스크립트 프로그래밍의 핵심적인 부분이다. 자바스크립트에는 객체를 설명하기 위한 기본 표기법인 JSON이 있다.

let campingSpot = {
  name:  “Willow Creek”,
  location: “Big Sur”
}
 
객체의 속성에 액세스하는 방법은 다음과 같다.

 
console.log(“We’re going camping at “ + campingSpot.name);
 
자바스크립트에서 객체는 JSON으로 제한되지 않는다. 함수 형태로 동작을 정의할 수도 있다(객체에 있을 때 메소드라고 함).

 
let campingSpot = {
  name:  “Willow Creek”,
  describeWater: function(){
    console.log(“Very cold”);
  }
}
 
또한 일회용 객체로 제한되지도 않으며 객체 클래스를 정의할 수도 있다.

class CampingSpot {
  constructor(name, location) {
    this.name = name;
    this.location = location;
  }
    describeWater() {
      console.log(“The water at ” + this.name + ” is very cold.”);
    }
}
이제 CampingSpot 객체의 인스턴스를 자유롭게 만들 수 있다.

OOP에 대해 자세히 알아보기
“역대 가장 중요한 SW 개발 혁신” 객체 지향 프로그래밍(OOP)의 이해‘에서 객체 지향 프로그래밍에 대해 더 자세히 알아볼 수 있다.


6. 원격 API 사용

서비스에 호스팅되는 API 액세스는 자바스크립트 프로그램에서 일반적으로 필요한 또 다른 작업이다. API는 외부 데이터와 기능에 대한 액세스를 제공한다. 개발자는 원격 API에서 데이터를 불러오고 응답을 파싱하고 애플리케이션에 통합하기 위한 방법을 찾는 경우가 많다.

다행히 현대 자바스크립트에는 클라이언트와 서버 환경 모두에 Fetch API가 포함된다. 이는 HTTP 호출을 위한 간단하고 직접적인 방법이다. 예를 들어 다음과 같은 방법으로 SWAPI 서비스에서 스타워즈 영화 목록을 가져올 수 있다.

async function getStarWarsFilms() {
  try {
    const response = await fetch(‘https://swapi.dev/api/films’);
    if (!response.ok) {
      throw new Error(`Error fetching Star Wars films: ${response.status}`);
    }
    const data = await response.json();
    console.log(data.results); 
  } catch (error) {
    console.error(“Error:”, error);
  }
}

getStarWarsFilms();
 
GET 요청이므로 fetch(‘https://swapi.dev/api/films’)를 사용하면 된다. 앞서 설명한 await를 사용한 것을 볼 수 있다. 요청이 나가고 응답이 돌아오는 사이 멈출 수 있게 해준다.

response 객체를 사용해서(response.ok) 요청이 정상적으로 처리되었는지 확인한다(HTTP 200 응답).


7. 문자열 조작

문자열은 기본적인 요소이며 모든 종류의 상황에 사용된다. 다음과 같은 문자열을 보자.

const taoTeChingVerse1 = 
  `The Tao that can be told is not the eternal Tao. 
  The name that can be named is not the eternal name. 
  The nameless is the beginning of heaven and earth. 
The named is the mother of all things,`;
 
첫 구절의 첫 번째 줄만 원한다고 가정해 보자.

const firstLine = taoTeChingVerse1.slice(0, 48);
 
이 코드는 ‘첫 번째 문자(0)부터 48번째 문자까지의 하위 문자열을 가져오라’는 의미다. 

“Tao”가 처음 나오는 부분을 검색하려면 다음을 입력한다.

taoTeChingVerse1.indexOf(“Tao”); // returns 4
 
단어를 교체하려면 간단한 정규식을 사용한다. 여기서는 모든 “told”를 “spoken”으로 대체한다.

 
const newText = text.replace(/told/g, “spoken”);
 
슬래시는 “told”와 매칭하는 정규식을 나타낸다. 접미사 g는 “global”, 즉 모든 발생을 의미한다. replace()의 두 번째 인수는 교체해 넣을 토큰이다. (최종적인 문자열은 “The Tao that can be spoken is not the eternal Tao.”가 된다.)

두 문자열을 연결해야 하는 경우 간단한 더하기(+) 연산자를 사용하면 된다.

let fullVerse = taoTeChingVerse1 + “Having both but not using them, Think of them as the constant.”);
 
또한 언제든 다음과 같이 문자열 길이를 계산할 수 있다.

fullVerse.length; // return 261
 


8. JSON 객체를 문자열로 변환

일반적으로 필요한 또 다른 작업은 실제 JSON 객체를 받아서 문자열로 변환하거나 그 반대로 변환하는 작업이다. 라이브 JSON 객체를 받아 문자열로 만드는 방법은 다음과 같다.

let website = {
  name: “InfoWorld”,
  url: “www.infoworld.com”
}

let myString = JSON.stringify(website);
 
다음은 문자열을 받아 객체로 되돌리는 방법이다.

JSON.parse(myString);
 


9. 간단한 날짜 연산

자바스크립트에 내장된 Date 객체로 많은 일을 할 수 있다.

우선 다음과 같이 오늘 날짜를 구할 수 있다.

const today = new Date();
 
또한 다음과 같이 날짜를 구성하는 각 부분을 구할 수 있다.

console.log(today.getFullYear());  // Get the year (e.g., 2024)
console.log(today.getMonth());    // Get the month (0-indexed, e.g., 4 for May)
console.log(today.getDate());     // Get the day of the month (e.g., 21)
console.log(today.getHours());    // Get hours (e.g., 13 for 1 PM)
console.log(today.getMinutes());  // Get minutes (e.g., 27)
console.log(today.getSeconds());  // Get seconds (e.g., 46)
 
다음은 7일 후를 구하는 방법이다.

date.setDate(date.getDate() + 7);
 
Date 객체에 대해 자세히 알아보기
Date 및 기타 주요 자바스크립트 객체에 대한 자세한 내용은 ‘자바스크립트 내장 객체 사용하기‘에서 볼 수 있다.


10. 숫자 만들기, 찾기, 세기

자바스크립트는 숫자를 아주 잘 다룬다. 대부분의 숫자를 기본적으로 처리하며, 부가적인 기능을 위해 내장 라이브러리인 Math를 제공한다.

다음과 같이 숫자를 만들 수 있다.

let age = 30;
let pi = 3.14159;
let billion = 1000000000;
 
또는 문자열에서 변환할 수 있다.

let convertedNumber = Number(“42”);
 
일반적인 작업의 동작 방식은 명확하다.

let addition = pi + 3; // addition now equals 6.14159
 
다음과 같이 신속하게 숫자를 반올림할 수 있다.

Math.ceil(pi); // round to nearest upper integer (4)
Math.floor(pi); // round to lowest int (3)
 
가장 큰 수를 찾으려면 다음과 같이 한다.

Math.max(100, 5, 10, 73);  // returns 100
 
배열을 시작하는 경우 스프레드 연산자를 사용할 수 있다.

let numbers = [100, 5, 10, 73];
Math.max(…numbers); // returns 100
 
마지막으로, 짝수 여부를 확인하는 방법은 다음과 같다.

let isEven = 10 % 2 === 0; // true (checks if remainder is 0)
dl-ciokorea@foundryco.com

Matthew Tyson
Contributing Writer

Matthew Tyson is a contributing writer at InfoWorld. A seasoned technology journalist and expert in enterprise software development, Matthew has written about programming, programming languages, language frameworks, application platforms, development tools, databases, cryptography, information security, cloud computing, and emerging technologies such as blockchain and machine learning for more than 15 years. His work has appeared in leading publications including InfoWorld, CIO, CSO Online, and IBM developerWorks. Matthew also has had the privilege of interviewing many tech luminaries including Brendan Eich, Grady Booch, Guillermo Rauch, and Martin Hellman.

Matthew’s diverse background encompasses full-stack development (Java, JVM languages such as Kotlin, JavaScript, Python, .NET), front-end development (Angular, React, Vue, Svelte) and back-end development (Spring Boot, Node.js, Django), software architecture, and IT infrastructure at companies ranging from startups to Fortune 500 enterprises. He is a trusted authority in critical technology areas such as database design (SQL and NoSQL), AI-assisted coding, agentic AI, open-source initiatives, enterprise integration, and cloud platforms, providing insightful analysis and practical guidance rooted in real-world experience.

이 저자의 추가 콘텐츠