ECMAScript 2025 : 자바스크립트의 주요 신기능
컨텐츠 정보
- 조회 381
본문
최신 자바스크립트 사양은 내장된 전역 Iterator, 새로운 Set 메소드, 개선된 정규식 등 유용하고 균형 잡힌 다양한 기능을 표준화해서 제공한다.
올해 자바스크립트 사양 업데이트는 많은 영역을 다룬다. 가장 주목할 만한 추가 요소는 새로운 내장 Iterator 객체와 그에 따르는 함수형 연산자이며 그 외에 새로운 Set 메소드, JSON 모듈 직접 가져오기, 정규식 개선, Promise 체인을 간소화하기 위한 새로운 Promise.try 메소드, 그리고 새로운 Float16Array 타입 배열 등이 있다.
자바스크립트의 최신 기능과 이를 활용해서 할 수 있는 일을 살펴보자.
Iterator 객체
먼저 가장 광범위한 영향을 미치는 Iterator 객체다. 사양에는 “이터레이터 작업을 위한 정적 및 프로토타입 메소드가 포함된 새로운 Iterator 전역 객체”라고 설명돼 있다.
모든 것의 출발점은 내장된 전역 Iterator 객체다(Devtools에서 F12를 눌러 자바스크립트 콘솔을 열면 볼 수 있음). 이 객체는 기존의 이터러블 객체를 map, filter와 같은 함수형 연산자를 제공하는 새로운 인터페이스로 래핑할 수 있게 해준다.
이 래퍼에는 두 가지 흥미로운 부분이 있다. 하나는 함수형 연산자가 없는 이터러블에 이를 제공함으로써 구문을 개선한다는 점, 다른 하나는 이를 게으르게(lazy) 구현하면서 요소를 인라인으로 평가한다는 점이다. 이는 특히 대규모 또는 스트리밍 컬렉션에서 성능상의 이점을 제공한다.
새로운 Iterator는 함수 생성기와 같이 함수형 연산자가 없는 단순한 이터레이터도 래핑할 수 있게 해준다. 즉, Array 및 다른 이터러블을 동일한 일관된 API 내에서 처리해서 성능상의 이득을 얻을 수 있다.
자바스크립트 Array는 내장된 함수형 연산자가 있지만 전체 배열을 즉시 평가하고 연산의 각 단계에서 중간 “작업 배열”을 생성하는 방식으로 작동하기 때문에 map이나 filter를 호출할 때마다 백그라운드에서 하위 배열이 생성된다. Iterator의 동작 방식은 예를 들어 자바 스트림과 같은 다른 함수형 프로그래밍 스타일 API와 비슷하다. 즉, 각 연산자가 요소 단위로 처리되고 최종 연산자에 도달할 때만 새로운 컬렉션이 생성된다.
몇 가지 간단한 예제를 보면 어떻게 작동하는지 이해할 수 있을 것이다. 먼저 똑똑한 사람들로 구성된 다음과 같은 배열이 있다고 가정해 보자.
let smarties = ["Plato","Lao Tzu","St. Augustine","Ibn Arabi","Max Planck","David Bohm"];
이 배열을 Iterator의 개선된 map 함수로 변환하려면 다음과 같이 할 수 있다.
Iterator.from(smarties).map(x => x.length).toArray(); // [5, 7, 13, 9, 10, 10]
여기서는 from()을 사용해서 Iterator 객체를 생성하며, toArray()는 최종 연산자다. 참고로 같은 작업을 Array.map으로도 수행할 수 있지만 내부적으로 Iterator.map()에 대한 구현은 게으르게 이뤄진다. 실제 동작을 살펴보기 위해 length을 기준으로 필터링한다고 가정해 보자.
Iterator.from(smarties).map(x => x.length).filter(x => x
take() 연산자를 추가한 것은 조건을 충족하는 처음 두 요소만 필요하다는 의미이므로 해당되는 두 요소까지만 처리된다. 즉, 원본 배열에서 조건을 충족하기 위해 필요한 일부만 처리된다.
Iterator.from(smarties).map(x => x.length).filter(x => x
다음으로, Iterator가 배열이 아닌 이터레이터를 어떻게 래핑하는지 살펴보자. 우선 동일한 출력을 생성하는 간단한 생성기는 다음과 같다.
function* getSmartiesNames() { yield "Plato"; yield "Lao Tzu"; yield "St. Augustine"; yield "Ibn Arabi"; yield "Max Planck"; yield "David Bohm";}이것을 Iterator로 래핑한다.
terator.from(getSmartiesNames()) .map(name => name.length) .filter(length => length
Array와 생성기가 이제 동일한 함수형 API를 갖고, 둘 모두 내부 최적화에 따른 혜택을 받는다. (물론 여기 나오는 예제들은 설명을 위해 아주 단순하게 만든 것이다.)
새로운 Set 메소드
자바스크립트의 경우 다른 언어만큼 Set 클래스가 자주 사용되지는 않는다. 나중에 추가됐기 때문이기도 하고, Array 객체가 워낙 보편적이고 유연하기 때문이기도 하다. 그러나 Set은 has 및 delete 연산에 대해 삽입 순서와 선형 시간을 유지하는 고유하고 정렬되지 않은 컬렉션을 보장한다. 집합 이론에서 파생된 새로운 메소드가 추가되면서 Set의 활용도는 더욱 높아졌다.
특히 SQL과 같은 언어에서 이미 사용해본 경험자라면 이 메소드를 쉽게 이해할 수 있고 매우 편리하기도 하다.
Set.intersection은 두 집합에서 동일한 요소를 찾는다.
let set =new Set(["A","B","C"]);let set2 = new Set(["C","D","E"]);set.intersection(set2); // yields {‘C’}Set은 중복값을 저장하지 않으므로 여기서 결과 Set에 'C' 요소는 한 번만 존재한다.
Set.difference는 왼쪽 집합에서 오른쪽 집합을 뺀다.
set.difference(set2); // yields {“A”,”B”}그 결과로 첫 번째 집합에는 있고 두 번째 집합에는 없는 요소들을 얻게 된다.
set.symetricDifference(set2); // yields {'A', 'B', 'D', 'E'}이 샘플에서 'C' 요소가 제거된 것은 두 집합에 공통적으로 존재하는 유일한 요소이기 때문이다.
이번 사양에는 집합 관계를 확인하기 위한 세 가지 새로운 메소드도 포함되는데, 이름만 봐도 기능을 대략 짐작할 수 있을 것이다.
isSubsetOf는 첫 번째 집합이 두 번째 집합에 완전히 포함되는지 확인한다.isSupersetOf는 첫 번째 집합이 두 번째 집합을 완전히 포함하는지 확인한다.isDisjointFrom는 두 집합이 서로 완전히 다른지 확인한다.
JSON을 모듈로 가져오기
ES2025는 JSON을 모듈로 직접 가져올 수 있는 기능을 표준으로 제공하므로 JSON 파일을 수동으로 가져오거나 이를 위해 빌드 단계를 사용할 필요가 없다. JSON 가져오기가 정말 간편해진 것이다.
import appConfig from './data.json' with { type: 'json' };appConfig의 내용은 이제 문자열이 아니라 파일의 실제 JSON 파싱된 객체다. 이 기능은 로컬 파일에 한해 작동하며 원격 위치에는 적용되지 않는다.
with 키워드는 사양에서 참조하는 모듈 속성을 가리키는데, 지금은 JSON 모듈의 타입을 JSON으로 지정하는 데만 사용된다(모듈의 내용을 자바스크립트로 해석할 가능성을 차단하기 위해 추가된 기능). 향후 with를 통해 다른 모듈 속성을 지정하는 것이 가능해질 수도 있다.
정규식 개선
새로운 RegExp.escape 정적 메소드는 정규식 문자열에 대한 인젝션 공격을 차단할 수 있게 해준다. 이 메소드는 정규식 컨텍스트에서 특수한 의미를 가진 모든 문자를 이스케이프 처리한다. 임의의 SQL 문자열에 대한 SQL 인젝션을 차단하는 함수와 비슷하다. 이 메소드 덕분에 신뢰할 수 없는 정규식 문자열도 안전하게 사용할 수 있다.
시스템 일부에서 사용자 입력을 받아 이를 정규식과 결합한다고 가정해 보자. 악의적인 사용자가 구문 오류를 일으키는 정규식을 추가할 수 있지만 RegExp.escape(userInput)을 먼저 실행하면 이러한 문제가 사전에 차단된다.
또 다른 개선으로, “정규식 내에서 수정자 플래그를 인라인으로 활성화 및 비활성화하는 구문이 추가”됐다.
이 개선은 정규식을 즐겨 사용하는 사람에게는 당연하게 느껴지지만 그 외의 사용자에게는 약간 난해할 수 있다. 개선의 요지는 정규식 내의 작은 일부분에만 플래그를 적용할 수 있도록 한 것이다. 예전에는 대소문자 구분과 같은 플래그가 식 전체에 적용됐기 때문에 식의 일부 섹션에만 플래그를 적용하기 위해서는 복잡한 우회 방법을 사용하거나 여러 정규식으로 나눠 실행할 수밖에 없었다.
이제 자체 플래그를 적용하는 하위 섹션을 정의할 수 있다. 예를 들어 비틀즈의 유명한 노래에 대한 다음과 같은 코드를 보자.
const beatlesLyrics = [ "All You Need Is Love", "Can't Buy Me Love", "A Hard Day's Night","Eight Days a Week", "Yesterday, all my troubles seemed so far away.","Love Me Do" ];
여기서 "love"를 대소문자 구분 없이, "Day"는 대소문자를 구분해 매치하려면 이전에는 마땅한 좋은 방법이 없었지만, 이제는 아주 쉽게 가능하다.
const beatlesSearchRegex = /(?i:Love)|(?-i:Day)/;
이 코드는 괄호 안의 두 부분(물음표는 캡처하지 않는 그룹, 즉 참조를 유지하지 않는 그룹을 나타냄)을 독립적인 플래그를 적용해 매치하라는 의미다. 여기서는 Love에는 대소문자 구분 무시를 의미하는 (i)를 적용하지만 Day에는 적용하지 않는다. 이 문자열 집합의 “Yesterday“에서 day는 소문자이므로 매칭되지 않는다.
새로운 Promise.try 메소드
사양에 따르면 새로운 Promise.try 메소드는 “Promise를 반환할 수도 있고 반환하지 않을 수도 있는 함수를 호출하고 결과가 항상 Promise가 되도록 보장하기 위한” 용도로 사용된다.
이 기능은 상당히 유용해서, Promise.try()로 Promise 체인을 래핑할 수 있게 해준다. 이렇게 하면 동기 오류가 체인으로 연결된 catch()에서 처리된다. 즉, 부가적인 try{} 블록을 생략하고 catch()를 사용해서 비동기 오류와 동기 오류를 모두 처리할 수 있다.
Promise.try(() => thisMightThrowSyncError("foobar")) .then(val => console.log("All is well", val)) .catch(err => console.error("Error:", err.message));또한 Promise.try는 내부에서 체인으로 연결된 작업에서 발생하는 모든 오류(동기 또는 비동기 불문)를 처리하므로 프로미스를 try 블록으로 나누지 않고 체인으로 연결할 수 있다.
Promise.try(() => possibleSyncError("foo")) .then(processedStep1 => possibleAsyncError("bar")) .then(processedStep2 => fanotherPossibleAssyncError("baz")) .then(finalResult => console.log("Success", finalResult)) .catch(error => console.error("All errors arrive here", error.message, "I am an error"));Promise.try의 또 다른 장점은 단순한 값이나 Promise를 반환하는 작업을 지능적으로 처리한다는 점이다. 예를 들어 캐시에 적중할 경우 캐시를 반환하고 네트워크 호출을 수행하는 경우 Promise를 반환하는 함수가 있다고 가정해 보자.
function fetchData(key) { if (cache[key]) { return cache[key]; } else { return new Promise(resolve => { setTimeout(() => { data = { id: key, name: `New Item ${key}`, source: "DB" }; cache[key] = data; }, 500); }); } }적중 여부에 관계없이 Promise.try는 호출을 받고 모든 오류를 catch 블록으로 라우팅한다.
Promise.try(() => fetchData("user:1")) .then(data => console.log("Result 1 (from cache):", data)) .catch(error => console.error("Error 1:", error.message));Float16Array TypedArray
이 업데이트에 대해서는 사양에 “새로운 Float16Array TypedArray 종류와 함께 관련 DataView.prototype.getFloat16, DataView.prototype.setFloat16, Math.f16round 메소드가 추가됐다”고 설명돼 있다.
Float16 타입은 애플리케이션이 메모리 사용량을 최대화하기 위해 정밀도를 타협해야 하는 고성능 컴퓨팅 분야에 사용된다. 이러한 분야에는 머신 러닝도 포함된다. 아마 애초에 머신 러닝을 염두에 두고 이 추가 기능을 개발했을 것이다.
자바스크립트에는 새로운 스칼라 숫자 타입이 추가되지 않았기 때문에 여전히 Number만 존재하지만, 이제는 Float16Array를 사용해 이 타입의 데이터 컬렉션을 저장할 수 있게 됐다. 자바스크립트 Number는 64비트 배정밀도 부동소수점 형식을 사용하지만 대량의 숫자를 사용하면서 약간의 정밀도 손실이 허용되는 경우(예를 들어 신경망의 가중치나 편향) 16비트를 사용해 상당한 정도의 최적화가 가능하다.
추가된 메소드는 모두 원시 바이너리 데이터 버퍼를 처리하고 Float16Array와 함께 작동한다.
DataView.prototype.getFloat16은 dataview에서 Float16을 읽을 수 있게 해준다(64비트 표현으로 반환됨):newView.getFloat16(0, true);
DataView.prototype.setFloat16은dataview에Float16을 쓸 수 있게 해준다.view.setFloat16(0, 3.14159, true);
Math.f16round는 Number가Float16으로 변환될 때 정밀도 손실이 발생하는지 여부를 확인한다.
결론
자바스크립트 운영진은 사양에 유용하고 적절한 새로운 언어 기능들을 도입하기 위한 노력을 이어오고 있다. 새롭게 표준화된 여러 기능은 신중하게 설계된 균형 잡힌 기능이라는 느낌을 주며, 이 글에서 살펴본 바와 같이 폭넓게 활용이 가능하다.
dl-itworldkorea@foundryco.com
관련자료
-
링크
-
이전
-
다음






