2020๋ ์ ๋ง์ ์ด๋ฏธ ๋ง์ด ์๊ณ ์๋ ES2015(ES6) ๋ค์๋ถํฐ์ธ ES2016๋ถํฐ ES2020๊น์ง ์๋ก ๋์จ ์๋ฐ์คํฌ๋ฆฝํธ ๊ธฐ๋ฅ๋ค์ ์ดํด๋ณด๋ ค๊ณ ํฉ๋๋ค.
๋ชจ๋ ์๊ฐํ๋ ๊ฑด ์๋๊ณ ๋น๊ต์ ๋์์ด ๋๋, ๋ํ์ ์ธ ๊ฒ๋ค์ ์ถ๋ ค ์๊ฐํฉ๋๋ค.
๋ํ ๊ธฐ์ด์ ์ธ ์ฌ์ ์ง์์ ์ค๋ช
์ ์๋ต๋ ์ ์์ต๋๋ค.
ES2016
Array.prototype.includes
๋ฐฐ์ด ๋ด์ฅ ํจ์ includes๊ฐ ์ถ๊ฐ๋์์ต๋๋ค.
['a', 'b', 'c'].includes('a') // true
์ฝ๋๋ฅผ ๋ณด๋ฉด ์ฝ๊ฒ ์ญํ ์ ์ ์ ์์ต๋๋ค. ๋ฐฐ์ด์ ์์ดํ ์ด ์กด์ฌํ๋์ง Boolean ๊ฐ์ ๋ฐํํฉ๋๋ค.
์ด ํจ์๋ก ์ด์ ['a','b','c'].indexOf('a') > -1
๋์ ์ข ๋ ๊ฐ๊ฒฐํ ์ฝ๋๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
Exponentiation operator
์ ๊ณฑ ์ฐ์ฐ์.
๊ธฐ์กด์ ์ ๊ณฑ์ Math์ pow ํจ์๋ฅผ ์ด์ฉํ์ ๊ฒ์
๋๋ค.
์ด์ ๋ ๊ฐ๋จํ๊ฒ **
์ฐ์ฐ์๋ก ๊ฐ๋ฅํ๊ฒ ๋์์ต๋๋ค.
let num = 2;
Math.pow(num, 10); // 1024
2 ** 10; // 1024
num **= 10;
num; // 1024
ES2017
String padding
๋ฌธ์์ด์ ์ฌ๋ฐฑ์ ์ฃผ๊ธฐ ์ํด ๋ฑ์ฅํ ๊ธฐ๋ฅ์ ๋๋ค. ์ฌ๋ฐฑ ๋ฟ๋ง ์๋๋ผ ๊ทธ ์ฌ๋ฐฑ์ ๋ณด์ถฉ ๋ฌธ์๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค.
์ฌ๋ฐฑ์ ์์ ๋ค์ ์ถ๊ฐํ ์ ์๊ฒ ๋ฉ๋๋ค.
padStart(targetLength [, padString])
padEnd(targetLength [, padString])
๊ฐ๋จํ ์๋ฅผ ํตํด ์ดํด๋ณด๊ฒ ์ต๋๋ค. start์ end์ ์ฐจ์ด๋ ์๋ค์ ์ฐจ์ด๋ฐ์ ์์ผ๋ start๋ง ์ดํด๋ด ๋๋ค.
1์
์ 01์
๊ณผ ๊ฐ์ด ๊ธธ์ด๋ฅผ ๋ง์ถฐ์ผ ํ ๊ฒฝ์ฐ๊ฐ ์๋ค ์ด๋ด๋ ์ฌ์ฉ ํ ์ ์์ต๋๋ค.
`1์`.padStart(1); // "1์"
`1์`.padStart(3); // " 1์"
`1์`.padStart(3, "0"); // "01์"
`1์`.padStart(7, "0AB"); // "0AB0A1์"
1๋ฒ์งธ ๋ผ์ธ์ฒ๋ผ ๋ฌธ์์ด๋ณด๋ค ์์ ์๋ฅผ ์ง์ ํ๋๋ผ๋ ๋ฌธ์์ด์ด ์๋ฆฌ๊ฑฐ๋ ํ์ง ์์ต๋๋ค
2๋ฒ์งธ ๋ผ์ธ์ ๋ฌธ์์ด์ ๊ธธ์ด๋ณด๋ค ํ๋ ๊ธด 3์ ๋ฃ์ด ํ๋์ ์ฌ๋ฐฑ์ด ์ถ๊ฐ๋ ๋ชจ์ต์ ๋๋ค.
3๋ฒ์งธ ๋ผ์ธ์ด ์ํ๋ ์๋์ธ ์ฝ๋์ ๋๋ค.
4๋ฒ์งธ ๋ผ์ธ์ฒ๋ผ ๋ณด์ถฉ ๋ฌธ์๋ฅผ ๋ฐฐ์ด๋ก ์์ฑํ๋ฉด ๋ฐฐ์ด์ ์ํ ๋ฐ๋ณตํ๋ฉฐ ์ฌ๋ฐฑ์ ์ฑ์ฐ๋ฉฐ 0, A, B๋ฅผ ์ฑ์ฐ๊ณ ๋ค์์ผ๋ก 0, A๊น์ง ์ฑ์์ง ๋ชจ์ต์ ๋ณผ ์ ์์ต๋๋ค.
Object.values()
Object์ ์ถ๊ฐ๋ values ๋ฉ์๋๋ ๊ฐ์ฒด์ key:value ์์ value ๊ฐ๋ค์ ๋ฐฐ์ด์ผ๋ก ๋ฐํํฉ๋๋ค.
const obj1 = {name: "Jhon", age: 24};
Object.values(obj1); // ["Jhon", 24]
Object.entries()
๊ฐ์ฒด ์์ ๋ชจ๋ ์์ฑ์ ๊ฐ๊ฐ key, value๊ฐ ๋ด๊ธด ๋ฐฐ์ด๋ก ํ๋์ ๋ฐฐ์ด์ ๋ด์ต๋๋ค. [[key, value], [key, value], [key, value] ...]
const obj1 = {name: "Jhon", age: 24};
Object.keys(obj1); // ["name", "age"]
Object.values(obj1); // ["Jhon", 24]
Object.entries(obj1); // [["name", "Jhone"], ["age", 24]]
Object.getOwnPropertyDescriptors()
Object์ ๊ธฐ์กด์ ์๋ getOwnPropertyDescriptor์ ์ด์ด ๋ณต์ํ s๊ฐ ๋ถ์ getOwnPropertyDescriptors ๋ฉ์๋๊ฐ ์ถ๊ฐ๋์์ต๋๋ค.
ํด๋น ๋ฉ์๋๋ฅผ ์ดํดํ๊ธฐ ์ํด์๋ ์ ํ ์ง์์ผ๋ก getOwnPropertyDescriptor๊ฐ ๋ฌด์์ธ์ง ์์์ผํ๋ฉฐ ์์ฑ ์ค๋ช ์์ ๋ค๊ฐ์ง ์์ฑ์ ์์์ผํฉ๋๋ค. (๋งํฌ ์ฐธ์กฐ)
๋ํ Object.defineProperties() ๊ฐ์ ๋ฉ์๋๋ฅผ ์๊ณ ์์ด์ผ ์ ์ฉํ๊ฒ ํ์ฉํ ๋ฐฉ๋ฒ์ด ์๊น๋๋ค. ์ฌ๊ธฐ์๋ ์์ธํ ์ค๋ช ์์ด ํด๋น ๋ฉ์๋์ ๋ํด์๋ง ์ค๋ช ํฉ๋๋ค.
Object.getOwnPropertyDescriptor(obj, prop)
๊ธฐ์กด์ getOwnPropertyDescriptor๋ ์ธ์๋ก ๊ฐ์ฒด์ ์์ฑ๋ช ์ ์ ๋ฌํด ํด๋น ์์ฑ์ ์์ฑ ์ค๋ช ์๋ฅผ ๋ฐํํ๋ ๋ฉ์๋์ ๋๋ค.
์ด์ ์ฌ๊ธฐ์ ์ค๋ช ํ๋ getOwnPropertyDescriptors๋ ์์ฑ๋ช ์ ์ ๋ฌํ์ง ์๊ณ ๊ฐ์ฒด๋ง ์ ๋ฌํจ์ผ๋ก ๊ฐ์ฒด๋ด์ ๋ชจ๋ ์์ฑ์ ๋ํ ์์ฑ ์ค๋ช ์๋ฅผ ๋ฐํํฉ๋๋ค.
Object.getOwnPropertyDescriptor(obj)
๋๊ฐ์ ์์ ์ ๋๋ค.
console.log(Object.getOwnPropertyDescriptor(obj1, "name"));
// Object {value: "Jhon", writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptors(obj1));
// Object {
// name: {value: "Jhon", writable: true, enumerable: true, configurable: true},
// age: {value: 24, writable: true, enumerable: true, configurable: true}
// }
Trailing commas
ํจ์์ ๋ง์ง๋ง ๋งค๊ฐ๋ณ์์ ์ธ์์๋ ์ฝค๋ง๋ฅผ ๋ฃ์ ์ ์์ต๋๋ค.
์๋์ ๊ฐ์ด ๋ง์ด์ฃ . ํด๋น ๊ธฐ๋ฅ์ด ์ ์ถ๊ฐ๋์๋์ง๋ ๋ค์ํ ์๊ฒฌ์ด ์์ต๋๋ค. ํฅ๋ฏธ๊ฐ ์๋ ๋ถ๋ค์ ํ๋ฒ ๊ฒ์ํด๋ณด์ธ์.
const foo = (a, b, c,) => {}
async/await
์ฌ์ค์ ES2017์ ํต์ฌ์ด๋ผ๊ณ ๋ณผ ์ ์์ต๋๋ค.
์๋ก์ด ๋น๋๊ธฐ ์ฒ๋ฆฌ ํจ์๋ก ๊ธฐ์กด์ Promise ๋ณด๋ค ๊ฐ๋ ์ฑ์ด ์ข์ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๊ฒ ๋์์ต๋๋ค. ์ ํ์ ์ผ๋ก ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ๋ํ ์ง์๊ณผ Promise์ ์ดํด๊ฐ ํ์ํฉ๋๋ค.
ํด๋น ๋ด์ฉ์ ์ฌ๊ธฐ์ ๊ฐ๋จํ ๋ค๋ฃจ๊ธฐ์๋ ์ค์ํ๊ณ ๋ด์ฉ์ด ๊ธธ์ด ๋ฐ๋ก ํฌ์คํ ์ ํ ์์ ์ ๋๋ค.
์๋ ๋งํฌ๋ async/await๋ฅผ ์ค๋ช ํ ์บกํดํ๊ต๋์ ํฌ์คํธ์ ๋๋ค.
CAPTAIN PANGYO - ์๋ฐ์คํฌ๋ฆฝํธ async์ await
ES2018
Rest/Spread Properties
๊ธฐ์กด์ ๋ฐฐ์ด์์ ์ฌ์ฉํ๋ rest/spread๋ฅผ ๊ฐ์ฒด์์๋ ์ฌ์ฉ๊ฐ๋ฅํ๊ฒ ๋์์ต๋๋ค.
// Rest
const { one, two, ...others } = { one: 1, two: 2, three: 3, four: 4, five: 5 }
console.log(one, two, others); // 1 2 {three: 3, four: 4, five: 5}
// Spread
const obj1 = {one, two, ... others};
console.log(obj); // {one: 1, two: 2, three: 3, four: 4, five: 5}
const obj2 = { one: 100, five: 500 };
const obj3 = { five: 5000 };
const obj = { ...obj1, ...obj2, ...obj3};
console.log(obj); // {one: 100, two: 2, three: 3, four: 4, five: 5000}
๋ง์ง๋ง ๋ผ์ธ์ obj์ ์ถ๋ ฅ์ ๋ณด๋ฉด ๊ฐ์ ์์ฑ ์ด๋ฆ์ ๋ํด์๋ ์์ ๊ฒ์ ๋ค์ ๊ฒ์ด ๋ฎ์ด์ด๋ค๋ ๊ฒ์ ์ ์ ์๋ค.
Promise.prototype.finally()
then, catch, finally์์ Promise๋ ๊ธฐ์กด์ then๊ณผ catch๋ง ๊ฐ๋ฅํ์ผ๋ ์ด์ finally๋ ์ถ๊ฐ๋์์ต๋๋ค.
Promise.resolve('reslove')
.then((res) => console.log('success'))
.catch((err) => console.log('fail'))
.finally(() => console.log('finally'))
Asynchronous iteration
๋น๋๊ธฐ ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๋ฅผ ์ํํ๋ ๊ฒ์ด ๊ฐ๋ฅํด์ก์ต๋๋ค.
์ดํด๋ฅผ ์ํด์๋ Promise, async/await์ ์ดํด๊ฐ ์ ํ๋ฉ๋๋ค.
for await (const req of requests) {
console.log(req)
}
ES2019
String.trimStart() & trimEnd()
๋ฌธ์์ด์ ์์ด๋ ๋ค์ ๊ณต๋ฐฑ์ ์ ๊ฑฐํ๋ค.
์์ ์ ๊ฑฐํ๋ trimStart์ ๋ค๋ฅผ ์ ๊ฑฐํ๋ trimEnd๊ฐ ์๋ค.
์๋ ์์ ๋ฅผ ๋ณด๋ฉด ์ฝ๊ฒ ์ดํดํ ์ ์๋ค.
const s = " hello world";
const e = "! ";
console.log(s + e + ';');
// " hello world! ;"
console.log(s.trimStart() + e.trimEnd() + ';');
// "hello world!;"
Optional Catch Binding
catch ๋งค๊ฐ๋ณ์ ์์ด๋ catch ๋ธ๋ก์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
try {
// some code
}
catch (err) {
// error handling code
}
์์ ๊ฐ์ด catch(err){}
๋๋ catch(){}
์ ๊ฐ์ด ์ฌ์ฉํ๋ ๊ฒ์ ์๋์ ๊ฐ์ด ์ฌ์ฉํ ์ ์์ต๋๋ค.
try {
// some code
}
catch {
// error handling code
}
Object.fromEntries()
์์์ ์ค๋ช
ํ Object.entries()
์ ์ ๋ฐ๋์
๋๋ค.
๊ฐ์ฒด๋ฅผ entries๋ก ๋ฐฐ์ด๋ก ๋ง๋ค์๋ค๋ฉด fromEntries๋ก ๋ค์ ๊ฐ์ฒด๋ก ๋ง๋ค ์ ์๋ค๋ ์ด์ผ๊ธฐ์ ๋๋ค. entires๋ฅผ ์ดํดํ๋ค๋ฉด ๊ฐ๋จํ๊ฒ ์๋ ์์ ๋ฅผ ํตํด ์ ์ ์์ต๋๋ค.
const obj1 = {name: "Jhon", age: 24};
const entries = Object.entries(obj1);
console.log(entries); // [["name", "Jhone"], ["age", 24]]
const fromEntries = Object.fromEntries(entries);
console.log(fromEntries); // {name: "Jhon", age: 24}
Array.flat() & flatMap()
flat ๋ฉ์๋๋ ๋ฐฐ์ด์์ ๋ฐฐ์ด์ ์ฝ๊ฒ ํฉ์น ์ ์๊ฒ ๋ฉ๋๋ค. ์์ ๋ฅผ ํตํด ์ฝ๊ฒ ์ดํดํ ์ ์์ต๋๋ค.
const arr = [1, , 2, [3, 4, [5, 6]]];
console.log(arr.flat()); // [1, 2, 3, 4, [5, 6]]
console.log(arr.flat(1)); // [1, 2, 3, 4, [5, 6]]
console.log(arr.flat(2)); // [1, 2, 3, 4, 5, 6]
flat์ ์ธ์๋ก๋ ๋ฐฐ์ด์ ๊น์ด๋ฅผ ๋๊ฒจ์ค ์ ์์ผ๋ฉฐ, ์ ๋ฌ๋ ์ธ์๊ฐ ์์ ๊ฒฝ์ฐ default๋ 1์ด๋ค. ๋ํ ๋น ๋ฐฐ์ด์ ๋ฌด์๋๋ค.
flatMap ๋ฉ์๋๋ map()
๊ณผ flat()
์ด ํฉ์ณ์ง ๊ฒ์ผ๋ก ๋ณผ ์ ์๋ค. ์ฐ์ map์ ํตํด ์๋ก์ด ๋ฐฐ์ด์ ๋ง๋ค๊ณ flat์ ํตํด ๋ฐฐ์ด์ด ํฉ์ณ์ง๋ค. (flatMap์ ๊น์ด๋ 1์
๋๋ค)
const arr = [1,2,3];
const map = arr.map(v => [v]);
const flatMap = arr.flatMap(v=> [v]);
console.log(map); // [[1], [2], [3]]
console.log(map.flat()); // [1, 2, 3]
console.log(flatMap); // [1, 2, 3]
ES2020
Dynamic Import
ํ์ผ import๋ฅผ ๋์ ์ผ๋ก ํ ์ ์๊ฒ ๋์์ต๋๋ค.
์๋ ์์ ๋ if๋ฌธ์ ๋ฐ๋ผ importํ ํ์ผ์ ์ฌ์ฉ ์ ๋ฌด๊ฐ ๋ฌ๋ผ์ง๋๋ฐ ์กฐ๊ฑด์ ๋ง์ง ์๋๋ผ๋ ์ผ๋จ์ ์ต์๋จ์ import๋ฅผ ํตํด ํ์ผ์ ๋ถ๋ฌ์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด์ ๋ ๋๋ฒ์งธ ์ฝ๋ ์์ ์ ๊ฐ์ด Dynamic Import๋ก ์ธํด ๋ถํ์ํ ๋์์ ์ค์ผ ์ ์๊ฒ ๋์์ต๋๋ค.
import config from './config.js';
if(response) {
age = config.age;
}
if(response) {
import('./config.js')
.then(config => {
age = config.age;
console.log(config);
}
}
์ฐธ๊ณ ๋ก Dynamic import ์์ ์ธ ๋๋ฒ์งธ ์ฝ๋์์ console.log์ ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ {age: 24, skills: ["react", "webpack"], default: "Jhon"}
์
๋๋ค.
๊ทธ๋ ๋ค๋ฉด config ํ์ผ์ ๋ด์ฉ์ ์๋์ ๊ฐ์ต๋๋ค.
export const age = 24;
export const skills = ["react", "webpack"];
export default "Jhon";
default๋ก export๋ฅผ ํ ๊ฒ์ default๋ผ๋ ์์ฑ ์ด๋ฆ์ ๊ฐ์ง๋ ๊ฒ์ ์์๋์ธ์.
BigInt
BigInt๋ 2^53
๋ณด๋ค ํฐ ์ ์๋ฅผ ์ทจ๊ธํ๊ธฐ ์ํด ๋ฑ์ฅํ์ต๋๋ค.
์ซ์ ๋ค์ n์ด ๋ถ๋ ํน์ง์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
์๋ก 10n
์ ์ซ์ 10
์ ๋ปํ๋ค๋ ์๋ฏธ์
๋๋ค.
์์ธํ ์์ ์ค๋ช ์ ์๋ ์์ ๋ก ์ค๋ช ํ๊ฒ ์ต๋๋ค.
const int1 = Number.MAX_SAFE_INTEGER + 1;
// 9007199254740992
const int2 = Number.MAX_SAFE_INTEGER + 2;
// 9007199254740992 <= ~993์ด ์๋๋ค.
const bigInt2 = BigInt(Number.MAX_SAFE_INTEGER) + 2n;
// 9007199254740993n <= ~993์ด ๋์๋ค.
console.log(typeof int1, typeof int2, typeof bigInt2);
// number number bigint
console.log(typeof 9007199254740993n); // bigint
console.log(9007199254740993n === bigInt2); // true
// ์ผ๋ฐ์ ์ธ ์ซ์ ๋ค์ n์ ๋ถ์ด๋ ๊ฒ์ผ๋ก bitint ํ์
์ ๊ฐ์ง๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
console.log(BigInt(10), BigInt(10n));
// 10n 10n <= BitInt์ ์ธ์๋ก๋ n์ ์ฌ๋ถ๊ฐ ์ค์ํ์ง ์๋ค.
console.log(10 === BigInt(10)); // false
console.log(10 == BigInt(10)); // true
// console.log(9007199254740993n + 1);
// ์ ์ฝ๋๋ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค. bigint๋ฅผ ์ฐ์ฐํ ๋๋ number ํ์
๊ณผ ์์ด์ฐ๋ ๊ฒ์ด ์๋๋ค.
Promise.allSettled
Promise.all()
์ ๋ชจ๋ ์์
์ด ์ฑ๊ณต(reslove)ํด์ผ ์คํ๋๋ ํน์ง๊ณผ ๋ฌ๋ฆฌ Promise.allSettled()
์ ๋์ค์ ์คํจ(reject)๋๋๋ผ๋ ๋ชจ๋ ์คํ์ ํ ์ ์์ต๋๋ค.
์๋ ์์ ๋ฅผ ํตํด ์ฝ๋์ ์คํ ๊ฒฐ๊ณผ๋ฅผ ์ดํด๋ด ์๋ค.
const p1 = new Promise((resolve, reject) => resolve("p1, resolved"));
const p2 = new Promise((resolve, reject) => resolve("p2, resolved"));
const p3 = new Promise((resolve, reject) => reject("p3, rejected"));
Promise.all([p1, p2, p3])
.then(response => console.log(response))
.catch(err => {
console.log(err);
});
/*
console.log(response)
{status: "fulfilled", value: "p1, resolved"}
{status: "fulfilled", value: "p2, resolved"}
{status: "rejected", reason: "p3, rejected"}
*/
Promise.allSettled([p1, p2, p3])
.then(response => console.log(response))
.catch(err => {
console.log(err);
});
/*
console.log(err);
p3, rejected
*/
Nullish Coalescing Operator
a ?? b
๋ก ๋ํ๋ด๋ ์ฐ์ฐ์์
๋๋ค. null
์ด๋ undefined
์ผ ๋๋ง b
๋ฅผ ๋ฐํํฉ๋๋ค.
0์ false๋ฅผ ์๋ฏธํ๊ธฐ๋ ํฉ๋๋ค.
๋ฐ๋ผ์ 0 || 'A'
๋ A
๊ฐ ๋ ๊ฒ๋๋ค.
ํ์ง๋ง 0์ด ์๋ฏธ์๋ ๊ฐ์ด๋ฉด 0 ๋ํ ์ฌ์ฉํด์ผ ํ ๊ฒ์
๋๋ค.
๋ํ ์ผํญ ์ฐ์ฐ์๋ฅผ ๋จ์ถ์์ผ ์ฌ์ฉํ ์ ์๋ ์ฅ์ ๋ ์์ต๋๋ค.
์์ ๋ฅผ ํตํด ์ดํด๋ด ์๋ค.
0 || 'A' // A
0 ?? 'A' // 0
0 ? 0 : 'A' // A
0 ?? 'A' // 0
Optional Chaining
foo.a.b
์ ์ ๊ทผํ๋ค๊ณ ํ์ ๋, a
๊ฐ ์๋ค๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค.
๋ฐ๋ผ์ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด if(foo.a && foo.a.b)
์ ๊ฐ์ด ์ฌ์ฉํ๊ณค ํฉ๋๋ค.
ํ์ง๋ง Optional Chaining์ ์ด์ฉํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง ์๊ณ undefined๋ฅผ ๋ฐํ๋ฐ์ต๋๋ค.
Optional Chaining์ foo.a?.b
์ ๊ฐ์ด ํํํฉ๋๋ค.
const foo = {
a: {
b: true
}
};
console.log(foo.a.b); // true
console.log(foo.b?.b); // undefined
console.log(foo.b.aa); // TypeError: Cannot read property 'aa' of undefined