[Javascipt] ECMAScript 2015(ES6) 그 이후 - (3) 클래스, 프로미스, 정규식
2025. 5. 29. 09:00ㆍJavascript/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
반응형
'Javascript > Javascript' 카테고리의 다른 글
[Javascript] 객체(Object) (1) | 2025.06.04 |
---|---|
[Javascript] let, const 그리고 var (1) | 2025.06.02 |
[Javascipt] ECMAScript 2015(ES6) 그 이후 - (2) 문자열, 배열, 객체 (1) | 2025.05.28 |
[Javascipt] ECMAScript 2015(ES6) 그 이후 - (1) 연산자 (2) | 2025.05.27 |
[Javascript] call, bind, apply (1) | 2025.05.26 |