[Javascipt] ECMAScript 2015(ES6) 그 이후 - (3) 클래스, 프로미스, 정규식

2025. 5. 29. 09:00Javascript/Javascript

728x90
반응형

 

 

 

자바스크립트의 혁명이라 할 수 있는 ECMAScript 2015(ES6) 이후 추가된 자바스크립트 최신 문법 중 자주 이용할 만한 기능들을 추려 정리해 보려 한다.

 

들어가기에 앞서 😡은 과거의 문법을, 😊은 최신 문법을 의미한다는 점을 참고해 봐주시길 바란다.

 

 

 

클래스 최신 문법

 

 

Class Field Declarations

  • 처음에는 클래스 인스턴스를 정의하기 위해서는 자바 같이 그냥 변수 선언으로 하면 에러가 나고 무조건 생성자(constructor) 내에서만 this를 통해 클래스 필드를 선언해야 했지만 이제는 바로 선언이 가능해졌다.
class Hello {
  fields = 0;
  title;
}

 

 

 

Static 키워드

  • static 키워드를 사용하여 정적 클래스 필드와 개인 정적 메서드를 제공.
class Hello {
  name = 'world';
  static title = 'here';
  static get title() { return title; }
}

new Hello().name // 'world'
Hello.title // 'here'

 

 

 

private 키워드

  • 자바의 private 기능을 추가.
  • 메서드와 필드명 앞에 "#"을 붙여서 private 메서드와 필드 정의가 가능.
  • "#"이 붙은 메서드와 필드는 private으로 동작하며 클래스 외부에서 접근이 되지 않음.
class ClassWithPrivateField {
  #privateField;

  constructor() {
    this.#privateField = 42;
  }
}

class SubClass extends ClassWithPrivateField {
  #subPrivateField;

  constructor() {
    super();
    this.#subPrivateField = 23;
  }
}

new SubClass(); // SubClass {#privateField: 42, #subPrivateField: 23}

 

class myClass {
    #privMethod(){
        return "프라이빗 메서드";
    }
    publicMethod(){
        return "퍼블릭 메서드";
    }    
}

let newClass = new myClass();
console.log(newClass.privMethod()); // ERROR

 

 

 

Ergonomic Brand Checks for Private Fields

  • private 속성/메서드를 체크.
  • public 필드에 대해 클래스의 존재하지 않는 필드에 접근을 시도하면 undefined 가 반환되는 반면에 private 필드는 undefined 대신 예외를 발생시키게 된다.
  • 따라서 in 키워드를 사용해 private 속성/메서드를 체크할 수 있음.
class VeryPrivate {
  constructor() {
    super()
  }

  #variable
  #method() {}
  get #getter() {}
  set #setter(text) {
    this.#variable = text
  }

  static isPrivate(obj) {
    return (
      #variable in obj && #method in obj && #getter in obj && #setter in obj
    )
  }
}

 

 

 


 

 

프로미스 최신 문법

 

Promise.all

 : 모든 프로미스가 이행될 때까지 기다렸다가 그 결과값을 담은 배열을 반환하는 메서드.

  • 여러 개의 프로미스가 모두 resolve(성공)된 후 다음 로직을 실행해야 하는 경우에 사용된다.
  • 복수의 URL에 request를 보내고 모든 요청의 응답이 올 때 화면을 렌더링해야 하는 상황이 그 예시.
  • 요청에 필요한 정보를 배열로 저장하고, 그 후 해당 정보를 프로미스로 매핑하여 Promise.all()에 입력하는 방법이 자주 쓰임.
  • 입력된 프로미스 배열이 하나라도 reject(실패)되면 Promise.all 또한 reject됨.
let urls = [
  'https://www.example.com/users/1',
  'https://www.example.com/product/2',
  'https://www.example.com/article/3'
];

// fetch를 사용해 url을 프라미스로 매핑
let requests = urls.map(url => fetch(url));

// Promise.all은 모든 작업이 리졸브 될 때까지 대기
Promise.all(requests)
  .then(responses => responses.forEach(
    response => alert(`${response.url}: ${response.status}`)
  ));

 

const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 200, 'foo2');
});
const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 300, 'foo3');
});
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo1');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});

// > Array ["foo2", "foo3", "foo1"]

 

Promise.all()은 인자를 배열로 받고, 배열 인자를 순서대로 비동기 결과를 출력해 준다.
위 코드와 같이 3번째 순서 프로미스 코드가 먼저 끝났다고 해서 결과 배열 인자가 뒤바뀌거나 그러지는 않는다.

 

 

 

Promise.any

 : 여러 개의 프로미스를 담은 배열을 인자로 받아서 프로미스 중 하나라도 결과가 반환되면 프로미스 조건을 만족하고 종료한다.

  • 여러 개의 프로미스 비동기 처리 중에서 하나라도 성공하면 모든 조건이 만족한 것으로 처리하는 구조.
const promise1 = new Promise((resolve) => setTimeout(resolve, 300, 'soso'));
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'quick'));
const promise3 = new Promise((resolve) => setTimeout(resolve, 500, 'slow'));

const promises = [promise1, promise2, promise3];


Promise.all(promises ).then((values) => {
  console.log(values);
});
// all은 모두 비동기응답이 와야 then 실행
// expected output: Array ["soso", "quick", "slow"] 


Promise.any(promises).then((value) => console.log(value)); 
// any는 하나라도 비동기 응답이 오면 then 실행
// expected output: "quick"

 

 

 

Promise.allSettled

  • Promise.allSettled()는 주어진 모든 프로미스를 이행하거나 거부한 후, 각 프로미스에 대한 결과를 나타내는 객체 배열을 반환한다.
const promiseArr = [
  new Promise((resolve, reject) => setTimeout(resolve, 1000, 'abc')),
  new Promise((resolve, reject) => setTimeout(reject, 2000)),
  new Promise((resolve, reject) => setTimeout(resolve, 3000)),
];

Promise.allSettled(promiseArr).then(data => console.log(data));
[
  {
    "status": "fulfilled",
    "value": "abc"
  },
  {
    "status": "rejected"
  },
  {
    "status": "fulfilled"
  }
]

 

 

 

Top-level Await

  • await 키워드를 사용하려면 무조건 async 함수가 필요해서 IIFE로 묶어 사용해 왔지만 이제 비동기 함수 및 클래스 외부에서 await 연산자를 선언하여 동기화 문제를 해결할 수 있다.
  • 단, 최상위 계층에서 await을 async 없이 사용할 수 있다는 것이지 함수 내에서 쓸 때 async가 전혀 필요없어졌다는 말이 아님을 유의하자.
import {getUser} from "./data/User"
let user = await getUser();

 

 

 


 

 

정규식 최신 문법

 

s 플래그(dotAll)

  • 원래 정규식의 . 표현식은 게행 문자를 제외한 모든 문자였으나 s플래그를 달면 게행식도 포함하게 된다.
/hi.welcome/.test('hi\nwelcome') // false
/hi.welcome/s.test('hi\nwelcome') // true

 

 

 

Regexp Match Indices

  • d 문자를 활용하여 일치하는 문자열의 시작 및 끝 인덱스가 있는 배열을 얻을 수 있다.
const re1 = /a+(?<Z>z)?/d;

// indices are relative to start of the input string:
const s1 = "xaaaz";
const m1 = re1.exec(s1);
m1.indices[0][0] === 1;
m1.indices[0][1] === 5;
s1.slice(...m1.indices[0]) === "aaaz";

 

 

named capture group

  • 미리 명명된 정규식 캡처 그룹 이름 지정
  • named capturing group: (?<name>x)
  • non-capturing group: (?:x)
const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
const result = re.exec('2015-01-02')

// result.groups.year === '2015';
// result.groups.month === '01';
// result.groups.day === '02';
// 이메일 주소를 정규식을 통해 ID와 도메인을 각각 email_id와 domain이란 이름으로 분리한 obj로 가져오기
const emailAddress = 'bloodguy@gmail.com';
 
const result = /(?<email_id>\w+)@(?<domain>\w+\.\w+)/.exec(emailAddress).groups
// { email_id: "bloodguy", domain: "gmail.com" }
  
// 필요한 게 ID만이라면 :?를 통해 그룹핑만 하고 결과값에서는 제외하는 것도 가능
const result2 = /(?<email_id>\w+)@(?:\w+\.\w+)/.exec(emailAddress).groups
// { email_id: "bloodguy" }

 

 

 

RegExp lookbehind assertions

  • ?= / ?! / ?<= / ?<!
  • 앞에 오는 항목에 따라 문자열 일치
// ?= 특정 하위 문자열이 뒤에 오는 문자열을 일치시키는데 사용
/Roger(?=Waters)/
/Roger(?= Waters)/.test('Roger is my dog') //false
/Roger(?= Waters)/.test('Roger is my dog and Roger Waters is a famous musician') //true

// ?! 문자열 뒤에 특정 하위 문자열이 오지 않는 경우 일치하는 역 연산을 수행
/Roger(?!Waters)/
/Roger(?! Waters)/.test('Roger is my dog') //true
/Roger(?! Waters)/.test('Roger Waters is a famous musician') //false

// ?<= 새로 추가된 표현식
/(?<=Roger) Waters/
/(?<=Roger) Waters/.test('Pink Waters is my dog') //false
/(?<=Roger) Waters/.test('Roger is my dog and Roger Waters is a famous musician') //true

// ?<! 새로 추가된 표현식
/(?<!Roger) Waters/
/(?<!Roger) Waters/.test('Pink Waters is my dog') //true
/(?<!Roger) Waters/.test('Roger is my dog and Roger Waters is a famous musician') //false

 

 

 

 

 

 

728x90
반응형