ES15(2024)의 5가지 놀라운 새로운 JavaScript 기능

반응형

올바른 형식의 유니코드 문자열

이 기능은 JavaScript가 유니코드 문자열을 처리하는 방식을 개선하는 것을 목표로 합니다. 유니코드 문자열은 다양한 언어와 기호의 문자를 효과적으로 표현하는 데 필수적입니다. 이 업데이트는 다양한 JavaScript 환경에서 이러한 문자열을 일관되고 정확하게 처리할 수 있도록 보장할 것입니다.

const sampleStrings = [
  // 혼자 있는 대리자를 사용한 예시
  "igor\uD800", // 선행 대리자
  "igor\uD800komolov", // 선행 대리자 뒤에 텍스트
  "\uDC00yourfuse", // 후행 대리자
  "your\uDC00fuse", // 후행 대리자 뒤에 텍스트
 
  // 잘 형성된 예시
  "yourFuse", // 대리자 없이 일반적인 문자열의 예시
  "emoji\uD83D\uDE00", // 완전한 대리자 쌍(이모티콘)을 포함한 문자열의 예시
];

sampleStrings.forEach(str => {
  console.log(`Processed String: ${str.toWellFormed()}`);
});
// Expected output:
// "Processed String: igor�"
// "Processed String: igor�komolov"
// "Processed String: �yourfuse"
// "Processed String: your�fuse"
// "Processed String: yourFuse"
// "Processed String: emoji😀"

위의 예시에서 toWellFormed() 메서드는 혼자 있는 대리자를 포함한 문자열 배열에 적용됩니다. 그 중 일부는 잘못된 문자열이고 일부는 잘 형성된 문자열입니다. 이 메서드는 혼자 있는 대리자를 포함한 문자열을 잘 형성된 유니코드 문자열로 변환하는데, 이 과정에서 잘못된 시퀀스를 대체 문자로 바꾸고 이미 잘 형성된 문자열은 변경하지 않습니다.

const problematicURL = "https://yourfuse.com/query=\uDC00data";

try {
  encodeURI(problematicURL);
} catch (e) {
  console.log('Error:', e.message); // Expected: URIError: URI malformed
}

// toWellFormed()를 사용하여 오류를 방지합니다.
console.log('Well Formed URI:', encodeURI(problematicURL.toWellFormed())); 
// Expected output: "https://yourfuse.com/query=%EF%BF%BDdata"
  • 문제가 될 수 있는 URL 변수에는 혼자 있는 후행 대리자(\uDC00)를 포함한 URL이 들어 있습니다.
  • encodeURI()를 사용하여 이 URL을 인코딩하려고 하면 잘못된 유니코드 문자열로 인해 URIError가 발생합니다.
  • WellFormed()를 적용하면 단일 서로게이트가 유니코드 대리자(U+FFFD, %EF%BF%BD로 인코딩됨)로 대체되어 encodeURI()가 오류 없이 이를 처리할 수 있습니다.

원자 waitSync

이 추가 사항은 공유 메모리 환경에서 특히 동시 작업을 대상으로 합니다. 이는 데이터 무결성을 보장하고 다중 스레드 작업에서 경쟁 조건을 방지하는 데 중요한 동기화 메커니즘을 제공합니다. 예를 들어, waitSync는 여러 작업자 간에 공유 버퍼에 대한 액세스를 동기화하는 데 사용될 수 있습니다.

아직 문서가 확정되지 않았으므로 예제가 없습니다. 따라서 어떻게 구현될지를 보여드릴 수는 없습니다. 그러나 기존의 Atomics 메서드를 기반으로 추측해볼 수 있습니다. 여기에 예상되는 구현 방법이 있습니다…

// 가정으로, sharedArray가 SharedArrayBuffer인 것으로 합니다.
const sharedArray = new Int32Array(new SharedArrayBuffer(1024));

function performSynchronizedOperation(index, value) {
  // waitSync 메서드는 특정 조건이 충족될 때까지 실행을 차단할 것입니다.
  // 예를 들어, 지정된 인덱스의 값이 0이 아닐 때까지 기다릴 수 있습니다.
  Atomics.waitSync(sharedArray, index, 0);
  // 공유 메모리에서 작업을 수행합니다.
  sharedArray[index] = value;
  // 인덱스의 값이 업데이트되었음을 다른 스레드나 워커에 알립니다.
  Atomics.notify(sharedArray, index, 1);
}

// 웹 워커나 다른 스레드에서 이를 수행합니다.
performSynchronizedOperation(0, 123);

RegExp v 플래그와 집합 표기법 + 문자열 속성에 대한 개선

JavaScript의 정규식에 대한 이 개선은 더 복잡한 패턴 매칭과 문자열 조작을 가능하게 합니다. ‘v’ 플래그와 집합 표기법을 사용하여 보다 정확하고 표현력 있는 정규식 패턴을 만들 수 있습니다. 예를 들어, 이 기능을 사용하여 특정 Unicode 속성을 가진 문자 집합을 일치시킬 수 있습니다.

// 차이/빼기
[A - B]

// 교집합
[A&&B]

// 중첩된 문자 클래스
[A - [0–9]]

A와 B는 문자 클래스(예: [a-z]) 또는 속성 이스케이프에 대한 자리 표시자로 간주될 수 있습니다. 제안에 대한 예시 및 FAQ입니다.

최상위 await

이 “Just Do It” 기능을 사용하면 await 키워드를 비동기 함수 외부에서도 사용할 수 있어서 비동기 코드를 작성하고 읽기 쉽게 만들 수 있습니다. 예를 들어, 모듈의 최상위 레벨에서 직접 promise를 await할 수 있으므로 모듈을 가져오거나 데이터를 비동기적으로 가져오는 코드를 간소화할 수 있습니다.

// With top-level await
const data = await fetchData();
console.log(data);

확실히, 이것은 무거운 비동기/대기 구조에 신선한 바람을 불어넣어줍니다!

파이프라인 연산자

파이프라인 연산자 (|>)는 여러 함수 호출이 있는 코드의 가독성을 향상시킵니다. 이를 통해 표현식의 결과를 다음 함수의 인수로 전달하는 함수형 스타일의 구문이 가능해집니다. 예를 들어, 중첩된 함수 호출을 명확한 연산 순서로 재구성할 수 있습니다.

// 파이프라인 연산자 사용하지 않는 경우,
const calculatedValue = Math.ceil(Math.pow(Math.max(0, -10), 1/3));

// 파이프라인 연산자 사용하는 경우,
const calculatedValue = -10
 |> (n => Math.max(0, n)) // Replacing Math.max
 |> (n => Math.pow(n, 1/3)) // Replacing Math.pow
 |> Math.ceil; // Using Math.ceil

이 예시에서:

  • Math.max 함수는 숫자가 음수가 아님을 보장합니다.
  • Math.pow 함수는 세제곱근을 계산합니다 (1/3 승으로).
  • Math.ceil 함수는 숫자를 가장 가까운 정수로 올림합니다.

파이프라인 연산자 (|>)는 이러한 연산들을 연결하는 것을 단순화하여 코드를 더 읽기 쉽게 만듭니다.

이제 다음은 데이터 변환에 대한 파이프라인 연산자의 유용성을 보여주는 예입니다.

// 파이프라인 연산자는 일련의 함수가 명확하고 간결한 방식으로 적용되도록 허용함으로써 복잡한 데이터 조작을 단순화합니다.
const numbers = [10, 20, 30, 40, 50];
const processedNumbers = numbers
 |> (_ => _.map(n => n / 2)) // 각 숫자를 반으로 나누는 것
 |> (_ => _.filter(n => n > 10)); // 10 이하의 숫자를 걸러내는 것
console.log(processedNumbers); // [15, 20, 25]

이 예시에서:

  • map 함수는 배열의 각 숫자를 절반으로 나눕니다.
  • 그런 다음 필터 기능은 10 이하의 모든 숫자를 제거합니다.
  • 파이프라인 연산자(|>)는 이러한 변환을 우아하게 연결하여 코드 가독성을 향상시킵니다.

파이프라인 연산자는 아직 TC39의 2단계 “초안”에 있다는 것을 기억하세요.

레코드와 튜플

이러한 불변 데이터 구조는 각각 객체와 배열과 유사하지만, 생성 후에는 수정할 수 없습니다. 예를 들어, 레코드나 튜플을 업데이트하면 새로운 인스턴스가 생성됩니다.

// 불변 레코드 생성
const userProfile = #{
  username: "IgorKomolov",
  age: 39,
};

// 불변 튜플 생성
const numberSequence = #[10, 20, 30];

// 이러한 구조를 업데이트하면 새 인스턴스가 생성됩니다.
const updatedProfile = userProfile.with({ age: 40});
console.log(updatedProfile); // #{ username: "IgorKomolov", age: 40 }
console.log(userProfile); // #{ username: "IgorKomolov", age: 39 } (그대로 유지됨)

const newNumberSequence = numberSequence.with(1, 25);
console.log(newNumberSequence); // #[10, 25, 30]
console.log(numberSequence); // #[10, 20, 30] (그대로 유지됨)

레코드는 객체와 유사하게 작동하고 튜플은 배열과 유사합니다. 그러나 정의적인 특징은 불변성입니다.

레코드와 튜플은 특정 상황에서 성능을 향상시키고 코드베이스에서 불변성을 강제할 수 있습니다. 이들은 제안의 2단계에 있으며 아직 JavaScript 엔진에 구현되지 않았지만, 개발자는 Babel과 같은 트랜스파일러를 사용하여 이들을 실험할 수 있습니다.

데코레이터

이것은 TypeScript에게 감사드립니다. 이것은 오랫동안 기다려져 왔으며 이제는 기본적으로 제공됩니다! 이들은 클래스, 메서드, 속성 또는 매개변수의 동작을 수정하거나 보완할 수 있게 해줍니다. 특히 메타데이터 추가, 로깅 또는 동작을 선언적인 방식으로 수정하는 데 유용합니다.

// 메소드 실행을 추적하기 위해 데코레이터 적용
class SampleClass {
  @trackExecution
  performAction(parameter1, parameter2) {
    // 메소드 구현이 여기에 표시됩니다.
  }
}

이 예시에서:

  • SampleClass는 정의되는 클래스입니다.
  • @trackExecution은 performAction 메서드의 호출을 로그하거나 추적하는 데 사용되는 데코레이터입니다.
  • performAction은 SampleClass 내부의 두 매개변수 (parameter1과 parameter2)를 가진 메서드입니다. 이 데코레이터는 이 메서드에 대한 각 호출을 로그하거나 추적합니다.

패턴 매칭

이 기능은 복잡한 데이터 구조를 구조화 및 일치시키고 코드 가독성을 향상시키며 상용구를 줄이기 위한 간결한 구문을 도입합니다.

(연구 중) 더 많은 내용이 곧 공개될 예정이니 나중에 다시 확인해 주세요!

Temporal

Temporal은 예전부터 초안이 작성되었지만, 업데이트된 Temporal은 JavaScript를 위해 제안된 현대적이고 포괄적인 날짜 및 시간 API로, 현재 3단계에 있으며, 기존 Date 객체의 많은 제한과 복잡성을 해결하기 위해 설계되었습니다. 여기에는 ES2024에서 Temporal을 사용하는 몇 가지 예시가 있습니다:

이 객체는 현재 시간을 나타내는 Temporal 값을 만들기 위한 여러 팩토리 메서드를 제공합니다.

UTC로 현재 순간 얻기

Temporal.Now.instant().toString()

특정 시간대에서 현재 시간대 날짜-시간 가져오기

Temporal.Now.zondedDateTimeISO('Asia/Shanghai').toString()

현재 일반 날짜-시간을 ISO 형식으로 가져오기

Temporal.Now.plainDateTimeISO().toString()

현재 일반 시간을 ISO 형식으로 가져오기

Temporal.Now.plainTimeISO().toString()

ZonedDateTime.prototype의 속성

Temporal의 ZonedDateTime 클래스에는 날짜-시간 정보를 세부적으로 조작하고 검색할 수 있는 여러 속성과 메서드가 있습니다.

  • 여기에는 달력, 시간대, 연도, 월, 일, 시간, 분, 초 및 나노초에 대한 getter가 포함됩니다.
  • 또한 .with(), .add(), .subtract(), .until(), .since() 및 .round()와 같은 메서드가 포함되어 있어 구역화된 날짜-시간 값 작업을 위한 광범위한 기능을 제공합니다.

Temporal 내의 Plain Time 클래스

Temporal은 시간대 없이 시간을 추상적으로 표현하는 “일반” 클래스를 도입합니다.

  • 이러한 클래스에는 PlainDateTime, PlainDate 및 PlainTime이 포함됩니다.
  • 이는 주어진 시간대의 벽시계 시간을 표시하거나 1984년 6월 첫 번째 화요일을 찾는 것과 같이 시간대가 관련 없는 시간 계산에 유용합니다.

이 예는 ES2024의 Temporal이 어떻게 JavaScript의 날짜-시간 처리를 단순화하고 향상시켜 개발자에게 더욱 강력하고 다양한 도구를 제공하는지 보여줍니다.

지금 사용하고 싶으세요? 문제 없습니다!

제안을 가져오거나 Babel Polyfill을 사용할 수 있습니다. 제안을 가져오는 방법은 다음과 같습니다…

// 맞습니다. 제안서를 가져올 수 있습니다 :) 
import { Temporal } from '@std/proposal-temporal';

// 기본
const now = Temporal.Now.zonedDateTimeISO('America/New_York');
console.log(now.toString());

// 조작 & 비교
const date = Temporal.PlainDate.from('2024–01–01');
const newDate = date.add({ days: 10 });
console.log(newDate.toString()); // Outputs '2024–01–11'

편안한 브랜드 체크

사용자 정의 클래스 및 데이터 구조에서 객체의 유형을 확인하는 것을 간단화하여 유형 검증을 보다 직관적이고 오류가 덜 발생할 수 있도록 합니다. 이로 인해 보일러플레이트를 더 이상 보지 않게 됩니다!

기존 방식(ES2024 이전)

class Book {
  #author;
  constructor(author) {
    this.#author = author;
  }

  static hasAuthorField(obj) {
    try {
      obj.#author; // Attempt to access the private field
      return true; // Access successful
    } catch (err) {
      if (err instanceof TypeError) {
        return false; // Access failed, field does not exist
      }
      throw err; // Other errors are re-thrown
    }
  }
}

// Example usage:
const myBook = new Book("Igor Komolov");
console.log(Book.hasAuthorField(myBook)); // Expected output: true
const otherObject = {};
console.log(Book.hasAuthorField(otherObject)); // Expected output: false

새로운 ES2024 방법

class BookES2024 {
  #author;
  constructor(author) {
    this.#author = author;
  }

  static hasAuthorField(obj) {
    return #author in obj; // New ES2024 syntax for checking private field
  }
}

// Example usage:
const myBook2024 = new BookES2024("Igor Komolov");
console.log(BookES2024.hasAuthorField(myBook2024)); // Expected output: true
const otherObject2024 = {};
console.log(BookES2024.hasAuthorField(otherObject2024)); // Expected output: false

이 예시에서, Book 클래스는 전통적인 방법을 보여주고 있습니다. 반면 BookES2024는 새로운 ES2024 구문을 사용합니다. hasAuthorField 정적 메서드는 각 클래스에서 서로 다른 접근 방식을 사용하여 객체에 private 필드 #author가 있는지 확인합니다.

Realms API

이 API는 격리된 JavaScript 환경을 생성하기 위한 메커니즘을 제공합니다. 안전한 코드 실행 및 샌드박싱에 유용하므로 제어되고 격리된 컨텍스트에서 코드를 실행할 수 있습니다. 게다가 이름도 정말 멋진 것 같아요!

Realm 생성 및 간단한 표현식 평가

const igorsRealm = new Realm();
igorsRealm.evaluate('3 * 5'); // Evaluates to 15 in Igor's realm

Realm 간 심볼 공유

const igorsRealm = new Realm();
Symbol.for('y') === igorsRealm.evaluate('Symbol.for("y")'); // returns true, shared symbol 'y'

자동 래핑된 함수 사용

호출 가능한 객체가 한 영역에서 다른 영역으로 전송되면 래핑된 함수 엑조틱 객체가 대상 영역에 생성됩니다. 이 래핑된 함수는 호출될 때 원래 영역에 연결된 함수에 대한 호출을 연결합니다.

const igorsRealm = new Realm();
const doubleFunction = igorsRealm.evaluate('num => num * 2');
doubleFunction(10); // returns 20

콜백을 사용한 함수 평가

const igorsRealm = new Realm();
const processNumber = igorsRealm.evaluate('(number, callback) => callback(number + 5)');
processNumber(5, (result => console.log(result))); // Logs 10 (5 + 5)

제한된 전역 컨텍스트 액세스

realm.evaluate를 통해 globalThis, 배열 또는 Object.prototype과 같은 전역 객체에 직접 액세스하면 TypeError가 발생합니다.

const igorsRealm = new Realm();
igorsRealm.evaluate('this'); // Throws a TypeError
igorsRealm.evaluate('new Array()'); // Throws a TypeError
igorsRealm.evaluate('Object.keys({})'); // Throws a TypeError

ES2024에서의 다가오는 기능들은 JavaScript 코딩에 접근하는 방식을 혁신할 것으로 기대됩니다. 이러한 향상은 코드의 가독성과 효율성을 향상시키는 것뿐만 아니라, 불변 데이터 구조와 고급 패턴 매칭과 같은 강력한 새로운 패러다임을 소개합니다. 이러한 기능들이 제안에서 구현으로 전환되면서, 개발자들에게 보다 깨끗하고 유지보수가 용이하며 표현력이 높은 JavaScript 코드를 작성할 수 있는 새로운 가능성이 열립니다. 이러한 발전으로 JavaScript의 미래는 빛나는 전망을 보여주며, 현대 웹 개발의 중요한 요소로 자리 잡은 언어의 지속적인 발전을 시사합니다.

반응형