[JS] ๐ ์๋ฐ์คํฌ๋ฆฝํธ ์ต์ ๋ฌธ๋ฒ ์ ๋ฆฌ - ECMAScript 2022
JavaScript ์ต์ ๋ฌธ๋ฒ ์ ๋ฆฌ (ES6 ~ ES13)
์๋ฐ์คํฌ๋ฆฝํธ์ ํ๋ช ์ด๋ผ ํ ์ ์๋ ECMASript 2015(ES6) ์ดํ ์ถ๊ฐ๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ต์ ๋ฌธ๋ฒ ์ค ์์ฃผ ์ด์ฉํ ๊ฒ ๊ฐ์ ๊ธฐ๋ฅ๋ค์ ์ถ๋ ค ์ ๋ฆฌํด๋ณธ๋ค.
์ ๋ง ํธํ ๊ธฐ๋ฅ๋ค์ด ๋ง์ผ๋ ์๋ฐ๋ C์ฒ๋ผ ์์ฝ๋ฉ์ผ๋ก ๊ตฌํํ๋ ค ํ์ง๋ง๊ณ ๋จ์ถ๋ฌธ๋ฒ์ผ๋ก ๊ฐ๋ฐ์๊ฐ์ ํ ์ค์ฌ๋ณด์!
...๋ค์ด๊ฐ๊ธฐ์ ์์,
๐ฉ ์ด๋ชจํฐ์ฝ์ ์๋ ๋ชป์๊ธด ๋ฌธ๋ฒ์ ์๋ฏธํ๋๊ฑฐ๊ณ ,
โจ ์ด๋ชจํฐ์ฝ์ ์ต์ ํธ๋ ๋ ๋ฌธ๋ฒ์ ์๋ฏธํ๋ ๊ฒ์ด๋ค.
ํธ๋ฆฌํ ์ฐ์ฐ์ ์ต์ ๋ฌธ๋ฒ
์ง์ ์ฐ์ฐ์
- ์์ฃผ ๊ฐ๋จํ๊ฒ ๊ณฑ์ ๊ธฐํธ๋ฅผ ๋๋ฒ์ฐ๋ฉด ์ ๊ณฑ์ผ๋ก ์ฒ๋ฆฌ
2**10 // 1024
Numeric separators
- 1000000000๊ณผ ๊ณผ ๊ฐ์ ๋จ์๊ฐ ํฐ ์ซ์์ ๊ฐ๋ ์ฑ์ ๋์ผ ์ ์๊ฒ ์ธ๋๋ฐ(_)๋ก ๋จ์๋ฅผ ๊ตฌ๋ถํ ์ ์๋ ํํ์ด ํ์ฉ.
- ex) 1_000_000_000๊ณผ ๊ฐ์ด ์ฒ ๋จ์๋ก ๋์ด์ ํ๊ธฐ๋ฅผ ํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ 0์ ๊ฐ์๋ฅผ ์ผ์ผ์ด ์ธ์ด ๋ณผ ํ์ ์์ด 10์ต์ด๋ผ๋ ์ซ์์์ ์กฐ๊ธ ๋ ์ฝ๊ฒ ์ ์ ์์.
- ๊ตฌ๋ถ์๋ ์์์ ์์น์ ๋ง๋๋ก ์ฝ์ ๊ฐ๋ฅ.
- ๊ทธ๋ฅ ๊ตฌ๋ถ์ ํํํ๋ ๊ฒ์ผ๋ฟ ๊ตฌ๋ถ์๊ฐ ์๋ค๊ณ ํด์ ์ซ์๊ฐ ๋ฌ๋ผ์ง๊ฑฐ๋ ๊ทธ๋ฌ์ง ์์
// โจ
console.log(1_000_000_000 + 10_000); // 1000010000
console.log(1_00_00_00 + 10_0); // 1000100
Tagged Template Literal
- ํจ์์ ์คํ์ ํ ํ๋ฆฟ ๋ฆฌํฐ๋ด๋ก ๊ตฌํ
const tag = (...args) => console.log(args);
tag`๋์ ์ ์ฒด๊ฐ ๋๋์ฒด ๋ญ๋?`;
// [["๋์ ์ ์ฒด๊ฐ ๋๋์ฒด ๋ญ๋?", raw: ['๋์ ์ ์ฒด๊ฐ ๋๋์ฒด ๋ญ๋']]]
const a = '์ ์ฒด๊ฐ';
const b = '๋ญ๋?';
tag`๋์ ${a} ๋๋์ฒด ${b}`;
// [['๋์ ', ' ๋๋์ฒด ', ' ', raw: ['๋์ ', ' ๋๋์ฒด ', '']], '์ ์ฒด๊ฐ', '๋ญ๋?']
Shorthand property names
- ํ๋กํผํฐ ์ด๋ฆ๊ณผ value๊ฐ์ ๋ณ์์ด๋ฆ๊ณผ ๋์ผํ ๋๋ ํ๋๋ก ์๋ต ๊ฐ๋ฅ
const ellie1 = {
name: 'Ellie',
age: '18',
};
const name = 'Ellie';
const age = '18';
// ๐ฉ
const ellie2 = {
name: name,
age: age,
};
// โจ
const ellie3 = {
name,
age,
};
let room = {
number: 23,
name: "hotel",
toJSON() {
return 9999;
}
};
let meetup = {
title: "Conference",
room
};
Destructuring Assignment
- ๊ตฌ์กฐ๋ถํด ๋ฌธ๋ฒ
- ๊ฐ์ฒด, ๋ฐฐ์ด์์ ์์๊ฐ๋ค์ ๋ฐ๊นฅ ๋ณ์๋ก ํ๋ฒ์ ๋นผ์ ์ฌ์ฉํ๊ธฐ ์ํ ๊ธฐ๋ฒ
// object
const student = {
name: 'Anna',
level: 1,
};
// ๐ฉ
const name = student.name;
const level = student.level;
console.log(name, level); // Anna 1
// โจ
const { name, level } = student;
console.log(name, level); // Anna 1
const { name: studentName, level: studentLevel } = student;
console.log(studentName, studentLevel); // Anna 1
// array
const animals = ['๐ถ', '๐ฝ'];
// ๐ฉ
const first = animals[0];
const second = animals[1];
console.log(first, second); // ๐ถ ๐ฝ
// โจ
const [first, second] = animals;
console.log(first, second); // ๐ถ ๐ฝ
Spread Syntax
- ์ ๊ฐ์ฐ์ฐ์
- ๊ฐ์ฒด๋ ๋ฐฐ์ด์ ์์ ์์๋ค์ ํผ์ณ ๋ณต์ฌ์ ์ด์ฉ. ์๊ธฐ ์์ ๊ฐ์ฒด, ๋ฐฐ์ด์ ์ํฅ ์๋ฐ์
- ํจ์์ ์๊ท๋จผํธ์ ์ฐ์ด๋ฉด, ๋๋จธ์ง ์ฐ์ฐ์๋ก ์์ฉ. ๋๋จธ์ง ์ธ์๊ฐ๋ค์ ๋ชจ์ ๋ฐฐ์ด๋ก ์์ฑ
const obj1 = { key: 'key1' };
const obj2 = { key: 'key2' };
const array = [obj1, obj2];
// array copy
const arrayCopy = [...array];
console.log(arrayCopy); // [ { key: 'key1' }, { key: 'key2' } ]
const arrayCopy2 = [...array, { key: 'key3' }];
obj1.key = 'newKey'; // array๋ฐฐ์ด์ ๋ํผ๋ฐ์ค ๊ฐ์ ๊ฐ๊ณ ์๋ ๋ฐฐ์ด์ด๋ค. ๊ทธ๋์ ์ ๊ฐ์ฐ์ฐ์๋ก ๋ณต์ฌํ์ฌ๋
// ๋ ํผ๋ฐ์ค ๋ณ์๋ ๋ณต์ฌ๋ก ์ทจ๊ธํ์ง๋ง, ๊ทธ๊ฑธ ์๋ ์ฃผ์์ฐ๊ฒฐ์ ๋๊ฐ๋ค.
console.log(array); // [ { key: 'newKey' }, { key: 'key2' } ]
console.log(arrayCopy2); // [ { key: 'newKey' }, { key: 'key2' }, { key: 'key3' } ]
// object copy
const obj3 = { ...obj1 };
console.log(obj3); // { key: 'newKey' }
// array concatenation
const fruits1 = ['๐', '๐'];
const fruits2 = ['๐', '๐ฅ'];
const fruits = [...fruits1, ...fruits2];
console.log(fruits); // [ '๐', '๐', '๐', '๐ฅ' ]
// object merge
const dog1 = { dog: '๐' };
const dog2 = { dog: '๐ถ' };
const dog = { ...dog1, ...dog2 };
console.log(dog); // { dog: '๐ถ' }
Short circuit
- ๋จ์ถ ํ๊ฐ.
- and์ฐ์ฐ์์ or์ฐ์ฐ์ ํน์ฑ์ ์ด์ฉํด ๋ฐํ๊ฐ์ ๊ฒฐ์ ํ๋ ๊ธฐ๋ฒ
โ
|| ์ฐ์ฐ์
const seaFood = {
name: "๋ฐ๋ฌ๋๊ฒ"
};
function getName(fish) {
/*if(!fish) {
return '์ด๋ฆ์์'
}
return fish;*/
return fish || '์ด๋ฆ์์' // ๋ง์ฝ fish๊ฐ null์ด๋ผ๋ฉด ๋์ or '์ด๋ฆ์์'์ ๋ฆฌํด
}
const name = getName(seaFood)
console.log(name) // {name : ๋ฐ๋ฌ๋๊ฒ}
const name2 = getName()
console.log(name2) // '์ด๋ฆ์์'
fish ๊ฐ Truthy ํ๋ฉด ์ผ์ชฝ ๊ฐ์ธ fish ๋ฅผ return ํ๊ณ
fish ๊ฐ Falsy ํ๋ฉด ์ค๋ฅธ์ชฝ ๊ฐ์ธ '์ด๋ฆ์์' ์ return ํ๋ค.
๋ช ์ ๋ก ์ ๋ฆฌํด๋ณด๋ค๋ฉด ์๋์ ๊ฐ๋ค.
- ์ผ์ชฝ ๊ฐ์ด Truthy ํ๋ฉด ์ผ์ชฝ ๊ฐ์ ๋ฆฌํดํ๋ค.
- ์ผ์ชฝ ๊ฐ์ด Falsy ํ๋ฉด ์ค๋ฅธ์ชฝ ๊ฐ์ ๋ฆฌํดํ๋ค.
console.log(false || 'hello') // 'hello'
console.log('' || 'hello') // 'hello'
console.log('ํธ๋ฃจ' || 'hello') // 'ํธ๋ฃจ'
console.log(1 || 'hello') // 1
console.log('hello1' || false) // 'hello1'
console.log('hello2' || NaN) // 'hello2'
console.log(null && false) // false
console.log(undefined || null) // null
var a;
var b = null;
var c = undefined;
var d = 4;
var e = 'five';
var f = a || b || c || d || e; // null, undefiend, ๋น๊ฐ์ falsyํ๋ค
console.log(f); // 4
&& ์ฐ์ฐ์
const seaFood = {
name: "ํนํฌ๋ฉ"
}
function getName(fish) {
/*if(fish) {
return fish.name;
}
return undefined*/
return fish && fish.name // ๋ง์ฝ fish๊ฐ ์ฐธ์ด๋ฉด, ์ฐ์ธก๊ฐ์ ๋ฆฌํดํ๋ค.
}
const name = getName(seaFood);
console.log(name); // 'ํนํฌ๋ฉ'
fish ๋ Truthy ํ๊ณ fish.name ๋ํ Truthy ํ๋ค๋ฉด ์ค๋ฅธ์ชฝ์ ๊ฐ์ return ํ๋ค.
๋ช ์ ๋ก ์ ๋ฆฌํด๋ณด๋ค๋ฉด ์๋์ ๊ฐ๋ค.
- ์ผ์ชฝ ๊ฐ์ด Truthy ํ๋ฉด ์ค๋ฅธ์ชฝ ๊ฐ์ด ๋ฆฌํด๋๋ค. ๋ง์ผ ์ค๋ฅธ์ชฝ ๊ฐ์ด ์์ผ๋ฉด undefined๋ null
- ์ผ์ชฝ ๊ฐ์ด Falsy ๋ฉด ์ผ์ชฝ ๊ฐ์ด ๋ฆฌํด๋๋ค.
console.log(true && "hello"); // 'hello'
console.log(null && undefined); // null
console.log(undefined && "hello"); // undefined
console.log("hello" && null); // null
console.log("hello" && "bye"); // bye
console.log(null && "hello"); // null
console.log(undefined && "hello"); // undefined
Nullish Coalescing Operator
- ?? ๋ฌธ๋ฒ
- ๊ฑฐ์ง์ ํ๋จ์ ์ ์ฐํ๊ฒ ํ๋จ. ๊ทธ๋ฅ ์ฌํํ๊ฒ ๊ฐ์ด ์๊ณ ์๊ณ ๋ก ํ๋จ
var named = 'Ellie';
var userName = named || 'Guest';
console.log(userName); // Ellie
var named = null;
var userName = named || 'Guest';
console.log(userName); // Guest
// ๐ฉ
var named = '';
var userName = named || 'Guest'; // ๋
ผ๋ฆฌ๊ฐ์ ๋น๊ฐ๋ false๋ก ํ๋จ
console.log(userName); // Guest
var num = 0;
var message = num || 'Hello'; // ๋
ผ๋ฆฌ๊ฐ์ 0์ false๋ก ํ๋จ
console.log(message); // Hello
// โจ
var named = '';
var userName = named ?? 'Guest'; // ๊ทธ๋ฅ ์ฌํํ๊ฒ ๊ฐ์ด ์๊ณ ์๊ณ ๋ก ํ๋จ. ๋น์นธ๋ ๊ฒฐ๊ตญ ๊ฐ์ด ๋น์นธ์ธ ๊ฒ์ด๋ค.
console.log(userName); // ''
var num = 0;
var message = num ?? 'Hello'; // 0๋ ๊ฒฐ๊ตญ ๊ฐ์ด 0์ธ๊ฒ
console.log(message); // 0
let a = null ?? 'hello';
let b = '' ?? true;
let c = false ?? true;
let d = 0 ?? 1;
let e = undefined ?? 'world';
console.log(a); // 'hello'
console.log(b); // ''
console.log(c); // false
console.log(d); // 0
console.log(e); // 'world'
Logical Operators and Assignment Expressions
- &&=, ||=
- ์์ Short circuit ๋จ์ถํ๊ฐ ||, && ์ ์ฐ์ฐ์์ += *= ๊ฐ์ ๋ฒ์ ผ
let oldName = 'oldPerson';
let newName = 'newPerson';
// -- if๋ฌธ์ ํตํ ๊ฐ ๋์
if(oldName) {
oldName = newName;
}
// && ์ฐ์ฐ์๋ฅผ ํ์ฉํ ๊ฐ ๋์
oldName && (oldName = newName);
// Logical Operators and Assignment Expressions (&&) ๋ฅผ ํตํ ๊ฐ ๋์
oldName &&= newName
let oldName;
let newName = 'newPerson';
// -- if๋ฌธ์ ํตํ ๊ฐ ๋์
if(!oldName) {
oldName = newName;
}
// && ์ฐ์ฐ์๋ฅผ ํ์ฉํ ๊ฐ ๋์
oldName || (oldName = newName);
// Logical Operators and Assignment Expressions (||) ๋ฅผ ํตํ ๊ฐ ๋์
oldName ||= newName
Logical nullish assignment
- ??=
x ??= y ์์x๊ฐ null ์ด๋ undefined ์ผ ๊ฒฝ์ฐ y๋ฅผ ๋์
const a = { duration: 50 };
// a.duration = a.duration ?? 10; ์ ๋จ์ถ ๋ฒ์
a.duration ??= 10; // a์ ์์ฑ์ duration ์์ฑ์ด ์์ผ๋ 10์ ๋ฌด์
console.log(a.duration); // expected output: 50
a.speed ??= 25; // a์ ์์ฑ์ speed ๋ผ๋ ํค๊ฐ ์์ผ๋ 25๊ฐ ๋ค์ด๊ฐ
console.log(a.speed); // expected output: 25
function config(options) {
options.duration ??= 100;
options.speed ??= 25;
return options;
}
config({ duration: 125 }); // { duration: 125, speed: 25 }
config({}); // { duration: 100, speed: 25 }
๋ฌธ์์ด ์ต์ ๋ฌธ๋ฒ
String.prototype.replaceAll()
- ์ผ์นํ๋ ๋ชจ๋ ๋ฌธ์์ด์ replace
- String.prototype.replace()๋ ์ฒ์ ๋์ค๋ ์ผ์นํ๋ ๋ฌธ์์ด๋ง ๋ฐ๊พธ๋ ๊ฒ. ๊ทธ๋์ ์ถ๊ฐ์ ์ผ๋ก ์ ๊ทํํ์์ ์ฌ์ฉํ์์ง๋ง ์ด์ ๋ ๊ทธ๋ด ํ์๊ฐ ์์ด์ก๋ค
// ๐ฉ
console.log("๋ฌธ์์ด์์ ์ฌ๋ฌ๋ฒ ๋์ค๋ ๋ฌธ์์ด์ ํ๊บผ๋ฒ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.".replace(/๋ฌธ์์ด/g,""));
// ์์ ์ฌ๋ฌ๋ฒ ๋์ค๋ ์ ํ๊บผ๋ฒ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
// โจ
console.log("๋ฌธ์์ด์์ ์ฌ๋ฌ๋ฒ ๋์ค๋ ๋ฌธ์์ด์ ํ๊บผ๋ฒ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.".replaceAll("๋ฌธ์์ด",""));
// ์์ ์ฌ๋ฌ๋ฒ ๋์ค๋ ์ ํ๊บผ๋ฒ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
String padding
- ๋ฌธ์์ด ๋ ๋ถ๋ถ์ด๋ ์์ ๋ถ๋ถ์ ๋ค๋ฅธ ๋ฌธ์์ด๋ก ์ฑ์ ์ฃผ์ด์ง ๊ธธ์ด๋ฅผ ๋ง์กฑํ๋ ์๋ก์ด ๋ฌธ์์ด์ ๋ง๋ค์ด๋ผ ์ ์๋ค.
"hello".padStart(6); // " hello"
"hello".padEnd(6); // "hello "
"hello".padStart(3); // "hello" // ๋ฌธ์์ด ๊ธธ์ด๋ณด๋ค ๋ชฉํ ๋ฌธ์์ด ๊ธธ์ด๊ฐ ์งง๋ค๋ฉด ์ฑ์๋ฃ์ง ์๊ณ ๊ทธ๋๋ก ๋ฐํ
"hello".padEnd(20, "*"); // "hello***************" // ์ฌ์ฉ์๊ฐ ์ง์ ํ ๊ฐ์ผ๋ก ์ฑ์ฐ๋ ๊ฒ๋ ๊ฐ๋ฅ
String.prototype.trimStart / trimEnd
- ๋น๊ณต๊ฐ์ ์ ๊ฑฐํ๋ trim์ ์ข๋ ์ธ๋ถํ
// trimStart()
'Testing'.trimStart() //'Testing'
' Testing'.trimStart() //'Testing'
' Testing '.trimStart() //'Testing '
'Testing '.trimStart() //'Testing '
// trimEnd()
'Testing'.trimEnd() //'Testing'
' Testing'.trimEnd() //' Testing'
' Testing '.trimEnd() //' Testing'
'Testing '.trimEnd() //'Testing'
๋ฐฐ์ด ์ต์ ๋ฌธ๋ฒ
Array.prototype.flat()
- ์ค์ฒฉ ๋ฐฐ์ด ์ญ์ / ๋น๊ณต๊ฐ ์ญ์
// ์ค์ฒฉ ๋ค์ฐจ์ ๋ฐฐ์ด ํํํ๊ฒ
const array = [1, [2, 3], [4, 5]];
array.flat(1); // ๊ฒฐ๊ณผ : [1,2,3,4,5]
// ๋ฐ์ดํฐ ์ ๋ฆฌ๋ ๋จ
const entries = ["bob", "sally", , , , , , , , "cindy"];
entries.flat(); // ๊ฒฐ๊ณผ ['bob', 'sally', 'cindy'];
// flat()
['Dog', ['Sheep', 'Wolf']].flat()
//[ 'Dog', 'Sheep', 'Wolf' ]
// flatMap()
let arr1 = ["it's Sunny in", "", "California"];
arr1.map(x=>x.split(" "));
// [["it's","Sunny","in"],[""],["California"]]
arr1.flatMap(x => x.split(" "));
// ["it's","Sunny","in", "", "California"]
Array.prototype.at()
- at() ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์์ ๋ฐ ์์ ์ธ๋ฑ์ค๋ฅผ ๋ชจ๋ ์ฌ์ฉํ์ฌ ๋ฌธ์์ด์ ์ธ๋ฑ์ฑํ ์ ์๋ค.
const arrays = ['a','b','c','d'];
console.log(arrays.at(-1)); // 'd
๊ฐ์ฒด ์ต์ ๋ฌธ๋ฒ
Optional chaining
- ?. ๋ฌธ๋ฒ
- ํ๋กํผํฐ๊ฐ ์๋ ์ค์ฒฉ ๊ฐ์ฒด๋ฅผ ์๋ฌ ์์ด ์์ ํ๊ฒ ์ ๊ทผํ ์ ์๋ค
- ?.์ ?.'์’์ ํ๊ฐ ๋์์ด undefined๋ null์ด๋ฉด ํ๊ฐ๋ฅผ ๋ฉ์ถ๊ณ undefined๋ฅผ ๋ฐํ. ํ๊ฐ๋์์ด true์ด๋ฉด ์ญ์ญ ์ด์ด๋๊ฐ ์ต์ข ๊ฐ์ ๋ฐํ
const person1 = {
name: 'Ellie',
job: {
title: 'S/W Engineer',
manager: {
name: 'Bob',
},
},
};
const person2 = {
name: 'Bob',
};
// ๐ฉ๐ฉ๐ฉ๐ฉ๐ฉ๐ฉ
function printManager(person) { // ์ค์ฒฉ ๊ฐ์ฒด์ ๊ฐ์ ๋ถ๋ฌ์ค๋ ํจ์
console.log(person.job.manager.name);
}
printManager(person1); // Bob
printManager(person2); // ์๋ฌ
// ๐ฉ
function printManager(person) {
console.log(person.job && person.job.manager && person.job.manager.name);
}
printManager(person1); // Bob
printManager(person2); // undefined
// โจ
function printManager(person) {
console.log(person?.job?.manager?.name);
}
printManager(person1); // Bob
printManager(person2); // undefined
?.() ํจ์ ์ ๊ทผ
let user1 = {
admin() {
alert("๊ด๋ฆฌ์ ๊ณ์ ์
๋๋ค.");
}
}
let user2 = {};
user1.admin?.(); // ๊ด๋ฆฌ์ ๊ณ์ ์
๋๋ค.
user2.admin?.(); // undefined
?.[] key ์ ๊ทผ
let user1 = {
firstName: "Violet"
};
let user2 = null; // user2๋ ๊ถํ์ด ์๋ ์ฌ์ฉ์๋ผ๊ณ ๊ฐ์ ํด๋ด
์๋ค.
let key = "firstName";
alert( user1?.[key] ); // Violet
alert( user2?.[key] ); // undefined
alert( user1?.[key]?.something?.not?.existing); // undefined
delete user?.name; // user๊ฐ ์กด์ฌํ๋ฉด user.name์ ์ญ์ ํฉ๋๋ค.
globalThis
- globalThis๋ ํ๊ฒฝ์ ๊ด๊ณ์์ด ์ ์ญ๊ฐ์ฒด๋ฅผ ํต์ผ๋ ๋ฐฉ๋ฒ์ผ๋ก ์ฐธ์กฐํ ์ ์๋ ๋ฐฉ๋ฒ์ด๋ค.
- ์๋๋ ๋ธ๋ผ์ฐ์ ์์์ ์ ์ญ(window)๊ณผ ๋ ธ๋์์์ ์ ์ญ(global)์ด ๋ฌ๋๋๋ฐ ์ด๋ฅผ ํต์ผํ ๊ฒ์ผ๋ก ๋ณด๋ฉด ๋๋ค.
// browser environment
console.log(globalThis); // => Window {...}
// node.js environment
console.log(globalThis); // => Object [global] {...}
// web worker environment
console.log(globalThis); // => DedicatedWorkerGlobalScope {...}
ํด๋์ค ์ต์ ๋ฌธ๋ฒ
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 ๊ธฐ๋ฅ์ ์ถ๊ฐ
- ๋ฉ์๋์ ํ๋๋ช ์์ "#"์ ๋ถ์ฌ์ ํ๋ผ์ด๋น ๋ฉ์๋์ ํ๋ ์ ์๊ฐ ๊ฐ๋ฅ.
- "#"์ด ๋ถ์ ๋ฉ์๋์ ํ๋๋ ํ๋ผ์ด๋น์ผ๋ก ๋์ํ๋ฉด ํด๋์ค ์ธ๋ถ์์ ์ ๊ทผ์ด ๋์ง ์๋๋ค.
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 ๋ํ ๋ฆฌ์ ํธ ๋๋ค.
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