기존에는 전역으로 string값을 수정하기 위해선 replace에 g(global) 옵션을 사용해야만 했는데
replaceAll로 간편하게 처리할 수 있게 되었다.
const 369Sentence = "12,45,78,"
console.log(369Sentence.replaceAll(",", "짝"); // 12짝45짝78짝
Promise.any()
는 iterable한 Promise
들을 인자로 받아 첫 번째로 해결된 Promise
가 생기면 바로 반환하는 메소드다. 모든 Promise가 reject 될 시에는 AggregateError
가 발생한다.
const differentDepartureTime = [
new Promise((res, rej) => setTimeout(res, 200, 'first')),
new Promise((res, rej) => setTimeout(res, 300, 'second')),
new Promise((res, rej) => setTimeout(res, 100, 'third')),
]
async function testPromise() {
const result = await Promise.any(differentDepartureTime)
console.log(result) // third
}
testPromise()
// 모두 reject로 가정 시
const differentDepartureTime = [
new Promise((res, rej) => setTimeout(rej, 200, 'first')),
new Promise((res, rej) => setTimeout(rej, 300, 'second')),
new Promise((res, rej) => setTimeout(rej, 100, 'third')),
]
// 출력 [AggregateError: All promises were rejected] {[errors]: [ 'first', 'second','third' ]}
기존에 자바스크립트 객체는 항상 강하게 참조가 되어서, 참고하고 있는 객체가 존재하고 있는 이상 객체가 가비지 컬렉팅 되지 않았다. 하지만 WeakRefs
가 나오게 되면서 약한 참조가 가능하게 되었고 이를 이용하면 가비지 콜렉터가 수집(?)할 수 있는 대상이 되기에 시간이 지나면 메모리로 환원이 될 수 있다..! 하지만 이는 사용을 하더라도 굉장히 숙고하여 사용해야한고 가능한한 사용을 피하는 편이 좋다고 한다.
deref()
메소드는 WeakRefs
객체의 속성을 확인 할 수 있고 Finalizers
라는 메소드를 통해 가비지 컬렉트가 되는 시점을 알 수 있어서 잘 조합하면 유용하게 사용할 수 있다.
이 부분에 대한 내용이 조금 많고 까다로워서 다음에 따로 포스팅하면 좋을 것 같다!
// 강한 참조
const map = new Map();
const obj = {data: new Array(10).join('*')};
map.set('someData', obj);
setInterval(() => {
console.log(map.get('someData').data);
}, 1000);
// (Infinity) **********
// 약한 참조
const map = new Map();
const obj = {data: new Array(10).join('*')};
map.set('someData', new WeakRef(obj));
setInterval(() => {
console.log(map.get('someData').deref().data);
}, 1000);
// (178) **********
// 환경마다 가비지 컬렉트 시간이 다를 수 있다.
세 가지의 논리 연산자가 추가 되었다. (&&=, ||=, ??=)
자주 쓰이는 +=와 같은 할당 연산자라고 보면 된다.
a &&= b // a = a && b
a ||= b // a = a || b
a ??= b // a = a ?? b
큰 숫자의 가독성을 높일 수 있게 언더바(_)
를 활용해 구분할 수 있게 되었다.
물론 언더바를 추가해도 연산이 가능하다
// 기존
console.log(1000000000 + 1000000) // 몇 자리지..?
// 변경
console.log(1_000_000_000 + 1_000_000) // 10자리 + 7자리구나!
기존에는 async/await은 한 세트로, await을 사용하기 위해서는 최상단에 항상 async를 적어줬어야했는데
2022버전부터는 최상위 레벨에서 await을 사용할 수 있게 되었다. 즉 모듈을 큰 async function처럼 작동하게 해준다.
// 기존
(async () => {
await AsyncFunction();
})
// 변경
(() => {
await AsyncFunction();
}
드디어 Array의 값으로 index를 사용할 때 음수를 사용할 수 있게 되었고, 드디어 Array의 마지막 값을 불러올 때 length를 구해서 array[length-1] 이런식으로 안해도 되게 되었다..만세!
// 기존
let arr = [1, 10, 100, 1000];
let length = arr.length;
console.log(arr[length-1]); // 1000
// 변경
let arr = [1, 10, 100, 1000];
console.log(arr.at(-1)); // 1000
기존의 Object.hasOwnProperty()
메서드와 거의 비슷한 역할을 하지만 이 메서드는 Object
의 프로토타입에 종속된 메서드이기 떄문에, 프로토타입이 없거나 재정의된 객체에서는 사용 불가능하다는 단점이 있었다.
이번에 추가된 Object.hasOwn()은 정적 메서드로 구현되어 특정 인스턴스의 프로토타입 상속 관계에 구애받지 않고 사용 가능하다는 장점이 있다.
let obj = {
props: "속성"
}
console.log(Object.hasOwn(obj, "props")) // true
Error.prototype.cause
는 에러체이닝을 위해 도입된 속성이다.
예뢰를 잡아서 다시 예외를 발생시킬 때 원래 발생한 오류에 접근할 수 있고, 보다 구체적인 혹은 유용한 에러 메세지를 추가할 때 사용한다.
function job1() {
try {
job2()
} catch (e) {
throw new Error("job1 Error", {cause: e})
}
function job2() {
throw new Error("job2 Error", {cause: "i don't know"})
}
}
try {
job1();
} catch (e) {
console.log(e);
console.log(e.cause)
}
/*
Error: job1 Error
at job1 (/Users/han/Desktop/coding/Algorithm/algorithm.js:6:15)
at Object.<anonymous> (/Users/han/Desktop/coding/Algorithm/algorithm.js:14:5)
... 5 lines matching cause stack trace ...
at node:internal/main/run_main_module:23:47 {
[cause]: Error: job2 Error
at job2 (/Users/han/Desktop/coding/Algorithm/algorithm.js:9:15)
at job1 (/Users/han/Desktop/coding/Algorithm/algorithm.js:4:9)
at Object.<anonymous> (/Users/han/Desktop/coding/Algorithm/algorithm.js:14:5)
at Module._compile (node:internal/modules/cjs/loader:1149:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1203:10)
at Module.load (node:internal/modules/cjs/loader:1027:32)
at Module._load (node:internal/modules/cjs/loader:868:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:23:47 {
[cause]: "i don't know"
}
}
Error: job2 Error
at job2 (/Users/han/Desktop/coding/Algorithm/algorithm.js:9:15)
at job1 (/Users/han/Desktop/coding/Algorithm/algorithm.js:4:9)
at Object.<anonymous> (/Users/han/Desktop/coding/Algorithm/algorithm.js:14:5)
at Module._compile (node:internal/modules/cjs/loader:1149:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1203:10)
at Module.load (node:internal/modules/cjs/loader:1027:32)
at Module._load (node:internal/modules/cjs/loader:868:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:23:47 {
[cause]: "i don't know"
}
*/
정규 표현식의 d flag
를 사용하면 패턴과 일치하는 문자의 시작과 끝 위치 정보를 얻을 수 있다.
기존에 특정 패턴과 일치하는 문자의 정보를 얻기 위해선 RegExp.prototype.exec
메서드를 사용했는데, 이 메서드는 일치하는 문자의 시작 인덱스 정보만을 제공한다는 단점이 있었다. 이러한 단점을 d flag
를 사용하여 해결할 수 있으며, 일치하는 문자열에 대한 인덱스 정보는 .indices
속성 안에 포함되어있다.
// 기존
const target = "bannana apple sweettomato";
const regExp = /\w{2}ple/g; // d flag 추가
const example = regExp.exec(target);
console.log(example);
/* =>
[
'apple',
index: 8,
input: 'bannana apple sweettomato',
groups: undefined
]
*/
// 변경
const target = "bannana apple sweettomato";
const regExp = /\w{2}ple/gdm; // d flag 추가
const example = regExp.exec(target);
console.log(example);
/* =>
[
'apple',
index: 8,
input: 'bannana apple sweettomato maple',
groups: undefined,
indices: [ [ 8, 13 ], groups: undefined ]
]
*/
이번 ES2022에서 가장 많은 변화가 있다는 Class Fields다.
Class Public Instance Fields
인스턴스 프로퍼티를 constructor
외부에서 선언할 수 있게 되었다.
기존에는 속성명 앞에 _
를 붙여 private 속성임을 암묵적으로 표시해 주었지만, 앞으로는 #
을 사용해 private 속성을 정의할 수 있다. 이 때 private 속성의 값을 외부로부터 주입받고 싶다면, 클래스 몸체에서 우선 정의를 해줘야한다.
class Person {
canFly = false;
#age;
constructor(name, age, phoneNumber) {
this.name = name;
this.#age = age;
this.#phoneNumber = phoneNumber; // Uncaught SyntaxError: Unexpected identifier
console.log(this.#age); // 17
}
}
const me = new Person("Jihoon", 17, "010-1111-2222");
console.log(me.isWorking); // false
console.log(me.name); // Jihoon
console.log(me.#age); // Uncaught SyntaxError: Private field '#age' must be declared in an enclosing class
Private Instance methods and accessors
인스턴스 프로퍼티뿐만 아니라 메서드와 접근자 프로퍼티(getter/setter)도 private 속성으로 정의할 수 있게 되었다.
class Person {
#job;
get #job() {
return this.#job;
}
set #job(work) {
this.#job = job;
}
constructor(work) {
this.#work = work;
}
Static class fields and private static methods
기존에는 클래스의 static 메서드는 클래스 몸체 밖에서 정의하였는데 앞으로는 static 키워드를 붙이는 것만으로 간단하게 static 메서드를 정의할 수 있다. (#을 붙임으로써 private으로 사용 가능)
class DailyFruit {
static #fruit = 'apple';
static amount = 5;
static getDailyFruit() {
return this.#fruit;
}
static #getDailyFruitAmount() {
return this.amount;
}
}
console.log(DailyFruit.getDailyFruit()); //'apple'
console.log(DailyFruit.amount); // 5
console.log(DailyFruit.#fruit); // SyntaxError
console.log(DailyFruit.#getDailyFruitAmount()); // SyntaxError
Ergonomic brand checks for Private Fields
private 필드가 존재하는 지를 클래스 내부에서 in 키워드를 통해 확인할 수 있다.
class Animal {
#mammal;
#amphibian;
#reptile;
static isExists(obj) {
return #mammal in obj && #amphibian in obj && #reptile in obj
}
}
const animal = new Animal();
Animai.isExists(animal);