자바스크립트 최신 메서드를 소개합니다
자바스크립트를 사용하는 개발자라 해도, ECMAScript에 어떤 기능이 새로 추가되고 있는지 잘 모르는 경우가 많습니다. 눈에 띄게 화려한 기능은 아니지만, 평소 우리가 반복해서 작성하던 코드를 훨씬 더 짧고 간결하게 바꿔주는 작고 실용적인 메서드들이 최근 몇 년 사이 꾸준히 추가되고 있습니다.
예를 들어, 배열에서 마지막 값을 꺼낼 때마다 arr[arr.length -1]을 사용했다면, 이제는 arr.at(-1)처럼 조금 더 직관적이고 간결한 방법이 생겼고, 객체의 속성이 존재하는지 확인할 때 매번 hasOwnProperty()를 사용했다면, 이제는 Object.hasOwn()이라는 훨씬 안전한 방식을 사용할 수 있습니다.

이번 글에서는 자바스크립트에 최근 새롭게 추가된 배열, 객체, 프로미스(Promise) 관련 메서드들을 소개해 보겠습니다. 이 메서드들은 복잡한 기능을 추가한 것이 아니라, 우리가 자주 쓰는 코드 패턴을 더 명확하고 간결하게 만들어 주는 기능입니다. 프론트엔드 개발자뿐만 아니라, 이제 막 자바스크립트를 배우기 시작한 입문자에게도 많은 도움이 될 것입니다.
또한 리액트(React)나 넥스트js(Next.js)를 사용하는 개발자들도 매우 유용하게 활용할 수 있습니다. 새로운 기능이라고 해서 어렵거나 부담스러운 것이 아니라, 오히려 익숙한 문제를 더 쉽고 간단하게 해결할 수 있도록 도와주는 도구라는 점을 함께 느껴 보시면 좋겠습니다.
배열을 더 짧고, 더 명확하게 다루는 방법
자바스크립트를 다루면서 가장 자주 마주하는 데이터 구조 중 하나는 바로 배열입니다. 반복문, 정렬, 필터링 등 다양한 상황에서 등장하는 만큼, 배열을 효과적으로 다루는 도구가 많을수록 생산성도 자연스럽게 높아지게 되죠. 최근 자바스크립트에서는 배열을 더 안전하고 읽기 쉽게 다룰 수 있는 새로운 메서드들이 등장했는데요. 하나씩 살펴볼게요.
1) .at()
배열에서 특정 위치의 값을 가져오는 일은 매우 흔한 작업입니다. 특히 마지막 요소를 가져와야 하는 경우, 우리는 오랫동안 arr[arr.length -1]이라는 문법에 익숙해져 있었습니다. 하지만 이 방식은 길이 계산이 필요하고, 읽는 사람 입장에서는 즉각적으로 “마지막 요소를 가져오려는 의도”가 명확하게 드러나지 않는다는 단점이 있었죠.
.at() 메서드는 이 문제를 간단하게 해결해 주는 도구입니다. 인덱스를 기준으로 요소를 반환하는 이 메서드는, 특히 음수 인덱스를 사용할 수 있다는 점에서 큰 차별점을 가집니다. arr.at(-1)이라고 작성하면 배열의 마지막 요소를 바로 얻을 수 있고, arr.at(-2)라고 작성하면, 뒤에서 두 번째 요소를 가져옵니다.
예를 들어, 사용자가 입력한 값들을 순서대로 배열에 저장해두고, 가장 최근 항목만 화면에 표시하고 싶을 때, .at(-1)을 사용하면 매우 직관적인 코드가 됩니다. 또한 배열이 비어 있는 경우에도 에러가 발생하지 않고 undefined를 반환하기 때문에, 조건문과 함께 쓰면 안전한 코드 작성이 가능합니다.
const fruits = ["apple", "banana", "grape"];
console.log(fruits.at(-1)) // grape
console.log(fruits.at(-2)) // banana
2) .groupBy()
다양한 데이터를 다룰 때 자주 하게 되는 작업 중 하나는, 특정 기준에 따라 항목들을 묶는 일입니다. 예를 들어, 게시글을 태그별로 구분하거나, 주문 목록을 결제 상태별로 나누거나, 유저 정보를 등급별로 분류하는 경우가 그렇습니다.
기존에는 이러한 분류 작업을 아래와 같이 reduce()로 직접 구현하거나, 외부 라이브러리를 사용해야 했습니다.

물론 이 방식도 잘 동작하지만, 코드가 길어지고 의도가 눈에 잘 드러나지 않는다는 단점이 있었는데요, 이제는 ECMAScript 2024에서 새롭게 표준으로 채택된 Array.prototype.groupBy() 메서드를 사용하면 훨씬 간결하고 명확한 코드로 같은 작업을 수행할 수 있습니다. 이 메서드는 배열의 각 요소에 대해 분류 기준이 되는 키를 반환하는 콜백 함수를 인자로 받아, 해당 키를 기준으로 항목들을 자동으로 그룹화해 객체 형태로 반환합니다.
const posts = [
{ id: 1, tag: "react", title: "useState 완전정복" },
{ id: 2, tag: "js", title: "클로저 쉽게 이해하기" },
{ id: 3, tag: "react", title: "useEffect 패턴" },
];
const groupedByTag = posts.groupBy(post => post.tag);
/*
{
react: [
{ id: 1, tag: "react", title: "useState 완전정복" },
{ id: 3, tag: "react", title: "useEffect 패턴" }
],
js: [
{ id: 2, tag: "js", title: "클로저 쉽게 이해하기" }
]
}
*/
이렇게 작성하면 reduce()로 수동 처리하던 복잡한 로직을 단 한 줄로 대체할 수 있고, 가독성도 훨씬 좋아집니다. groupBy()는 특히 서버에서 받아온 데이터를 카테고리별로 묶어 리스트를 나눠 보여주는 UI를 만들 때 아주 유용합니다. 예를 들어, 날짜별로 할 일을 그룹화하거나 상태값(status)에 따라 이슈를 나누는 기능을 구현할 때, 이 메서드를 활용하면 훨씬 간결하고 직관적인 코드를 작성할 수 있습니다.
3) .toSorted()
배열을 정렬하는 작업은 데이터 가공의 기본 중 기본이죠. 숫자를 오름차순으로 정렬하거나, 텍스트를 알파벳순으로 나열하는 등의 작업은 거의 모든 웹 애플리케이션에서 필요합니다. 그동안 자바스크립트에서는 Array.prototype.sort()를 사용해서 정렬해 왔었는데요. 이 메서드는 정렬 결과를 반환하는 동시에 원본 배열을 직접 수정한다는 특징을 가지고 있습니다. 이러한 특징은 의도치 않은 부작용을 일으킬 수 있어 주의해서 사용해야 했습니다.
이런 문제를 해결하기 위해 등장한 것이 바로 toSorted()입니다. 이 메서드는 기존 배열을 변경하지 않고, 정렬된 새로운 배열을 반환합니다. 즉, 원본을 그대로 두고 복사본을 정렬하는 방식이기 때문에 데이터의 불변성을 지켜야 하는 상황에서도 매우 유용하게 쓰입니다.
const prices = [4000, 1000, 3000];
const sortedPrices = prices.toSorted((a, b) => a - b);
console.log(sortedPrices); // [1000, 3000, 4000]
console.log(prices); // [4000, 1000, 3000] (원본은 그대로)
실무에서 상품 가격 목록을 오름차순으로 정렬하거나, 기록을 날짜 순으로 정렬할 때 원본 데이터를 유지하면서 정렬된 데이터를 따로 보여줘야 하는 경우가 많은데요. 이럴 때 이렇게 toSorted()를 활용하면 slice().sort()처럼 우회하지 않고도 더욱 직관적인 코드를 작성할 수 있습니다.
객체를 더 안전하게 다루는 방법
자바스크립트의 객체는 매우 유연한 구조를 가지고 있습니다. 이런 유연함 덕분에 다양한 데이터 구조를 표현할 수 있지만, 동시에 예기치 않은 버그가 발생하기 쉬운 부분이기도 합니다. 최근 자바스크립트에서는 객체를 더욱 명확하고 안전하게 다룰 수 있도록 몇 가지 유용한 메서드가 새로 도입되었습니다. 그중에서도 Object.hasOwn()과 Object.groupBy()는 객체 검사 및 데이터 분류 작업에 큰 도움이 됩니다. 하나씩 살펴볼게요.
1) Object.hasOwn()
객체에 특정 속성이 있는지를 확인할 때 흔히 사용하는 방식은 obj.hasOwnProperty(key)입니다. 하지만 이 방식은 몇 가지 문제를 가지고 있는데요. hasOwnProperty()는 객체가 직접 가진 메서드가 아니라 Object.prototype으로부터 상속받은 것이기 때문에, 객체에 해당 프로토타입을 제거했거나 속성을 덮어썼을 경우 제대로 동작하지 않을 수 있습니다.
이 문제를 해결하기 위해 등장한 것이 바로 Object.hasOwn()입니다. 이 메서드는 첫 번째 인자로 객체를, 두 번째 인자로 속성 키를 받아, 해당 키가 그 객체 자체에서 직접 존재하는지를 안전하게 판단합니다. 특히 Object.create(null)과 같이 프로토타입이 없는 순수한 객체에서도 예외 없이 안정적으로 사용할 수 있다는 점이 핵심입니다. 예를 들어, 아래의 코드를 보겠습니다.
const settings = Object.create(null);
settings.theme = "dark";
console.log(settings.hasOwnProperty); // undefined
console.log(Object.hasOwn(settings, "theme")); // true
여기서 Object.create(null)을 사용해 만든 settings 객체는 Object.prototype을 상속받지 않습니다. 즉, 일반 객체처럼 .hasOwnProperty라는 메서드를 내장하고 있지 않아, settings.hasOwnProperty를 호출하면 undefined가 출력되고, 만약 이를 사용하려고 하면 에러가 발생하게 됩니다.
하지만 Object.hasOwn(settings, ‘theme’)을 사용하면 문제없이 ‘theme’라는 속성이 settings에 존재하는지를 확인할 수 있습니다. 이처럼 Object.hasOwn()은 모든 종류의 객체에 대해 안전하게 속성 존재 여부를 확인할 수 있는 표준적인 방법이므로, 앞으로는 hasOwnProperty()보다 이 메서드를 우선적으로 사용하는 것이 바람직하다고 할 수 있습니다.
2) Object.groupBy()
배열 데이터를 조건에 따라 나누고, 이를 객체의 형태로 정리해서 활용해야 하는 상황은 매우 흔합니다. 예를 들어, 게시글을 작성일 기준으로 묶거나, 고객 데이터를 등급별로 구분하거나, 이벤트 로그를 레벨별로 분류하는 등의 작업이 있죠.
이러한 작업은 Object.groupBy()를 사용하면 편하게 처리할 수 있습니다. 이 메서드는 Array.prototype.groupBy()와 유사한 동작을 하지만, Object 객체의 정적 메서드로 정의되어 있다는 점이 다릅니다. 두 메서드 모두 결과를 일반 객체 형태로 반환하며, 그룹화된 키는 문자열로 변환되기 때문에 JSON 직렬화에 유리하고, UI 렌더링이나 조건 분기에도 쉽게 활용할 수 있습니다. 예를 들어, 학생 데이터를 학년(grade) 기준으로 그룹화하고 싶을 때 다음과 같이 사용할 수 있습니다.
const students = [
{ name: "혜진", grade: 1 },
{ name: "민수", grade: 2 },
{ name: "수지", grade: 1 },
{ name: "지훈", grade: 3 }
];
const groupedByGrade = Object.groupBy(students, student => student.grade);
/*
{
1: [
{ name: "혜진", grade: 1 },
{ name: "수지", grade: 1 }
],
2: [
{ name: "민수", grade: 2 }
],
3: [
{ name: "지훈", grade: 3 }
]
}
*/
이 메서드는 사용자 목록을 역할별로 분류하거나, 상품 데이터를 카테고리별로 정리해야 할 때처럼, 프론트엔드에서 자주 마주치는 UI 구조를 손쉽게 뒷받침하는 도구로 매우 효과적입니다. 기존에는 reduce()를 이용해 비교적 복잡한 코드를 작성해야 했다면, 이제는 Object.groupBy() 하나로 의도가 명확한 코드를 작성할 수 있습니다.
비동기 흐름을 더 유연하게 다루는 방법
자바스크립트는 비동기 처리를 기본으로 하는 언어입니다. 네트워크 요청, 타이머, 사용자 인터랙션 등 대부분의 작업이 비동기 흐름 안에서 처리되죠. 하지만 때로는 단순한 fetch() 호출만으로 해결되지 않는 복잡한 흐름이 필요합니다. 예를 들어, 특정 조건이 충족될 때까지 기다렸다가 처리하거나, 사용자 행동을 기다리는 구조 등입니다.

기존에는 new Promise()를 생성하고, 외부에 resolve나 reject를 꺼내 사용하는 방식이 일반적이었지만, 이 방식은 반복적으로 사용할수록 코드가 지저분해지고, 유지보수도 어려워질 수 있는데요. 이러한 문제를 해결하기 위해 등장한 메서드를 살펴보겠습니다.
1) Promise.withResolvers()
위에서 언급한 문제를 해결하기 위해 등장한 메서드가 바로 Promise.withResolvers()입니다. 이 메서드를 사용하면 promise, resolve, reject를 한 번에 얻을 수 있어서, 외부에서 비동기 흐름을 직접 제어하기가 훨씬 쉬워집니다. 하지만 Promise.withResolvers()는 현재 ECMAScript 표준에는 포함되어 있지 않으며, 아직 제안 단계에 있는 상태입니다. 일부 환경에서는 사용 가능하지만, 구 브라우저나 런타임에서는 직접 구현이 필요할 수 있다는 점을 주의해야 합니다.
const { promise, resolve } = Promise.withResolvers();
setTimeout(() => {
resolve("완료되었습니다!");
}, 1000);
promise.then(result => {
console.log(result); // "완료되었습니다!"
});
이러한 구조는 특히 사용자 액션을 기다려야 하는 상황에서 매우 유용하게 사용됩니다. 예를 들어, 사용자가 확인 버튼을 눌러야만 다음 단계로 진행되는 모달을 생각해 볼 수 있는데요, 예제 코드를 통해 살펴보겠습니다.
function showConfirmModal() {
const { promise, resolve } = Promise.withResolvers();
openModal({ onConfirm: resolve }); // 확인 시 resolve 호출
return promise;
}
async function handleDelete() {
const confirmed = await showConfirmModal();
if (confirmed) {
deleteItem();
}
}
기존에는 콜백 지옥이 생기거나, 상태를 복잡하게 구성해야 했던 흐름도, 위의 코드와 같이 Promise.withResolvers()를 사용하면 훨씬 간결하고 선언적인 방식으로 구현 가능합니다.
마치며
지금까지 살펴본 메서드들은 .at(), Array.prototype.groupBy(), .toSorted(), Object.hasOwn(), Object.groupBy(), Promise.withResolvers()처럼 크고 복잡한 기능이 아닙니다. 하지만 우리가 매일 반복하는 코드, 즉 배열에서 값을 꺼내고, 데이터를 그룹화하고, 객체 속성을 확인하고, 비동기 흐름을 다루는 작업을 더 안전하고 읽기 좋게 바꿔주는 작지만 강력한 도구라고 할 수 있습니다.
이 글에서 소개한 메서드들을 사용하면 기존보다 더 짧고 명확하게 코드를 작성할 수 있습니다. 또한 버그를 줄일 수 있고, 협업에서도 의도를 더욱 쉽게 전달할 수 있습니다. 특히 React나 Next.js를 사용하는 프로젝트에서는 상태 불변성과 조건 분기가 많아, 이 메서드들이 주는 장점이 더 크게 느껴질 겁니다. 최신 문법이라고 해서 무조건 어렵거나 무거운 것은 아닙니다. 오히려 지금까지 복잡하게 풀던 문제를 더 단순하고, 쉽게 해결할 수 있는 방법을 알게 되는 쪽에 가깝습니다. 이제 여러분의 프로젝트에도 하나씩 적용해 보며, 기능들을 익혀보시길 추천합니다.
©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.