Ecma 인터내셔널
은 정보 통신에 대한 표준을 제정하는 비영리 표준화 기구이다.ECMA-262
는 Ecma 인터내셔널
에 의해 제정된 하나의 기술 규격의 이름으로, 범용 목적의 스크립트 언어에 대한 명세를 담고 있다.ECMAScript
는 Ecma 인터내셔널
에 의해 제정된 ECMA-262
기술 규격에 의해 정의된 범용 스크립트 언어이다.ECMAScript
는 스크립트 언어가 준수해야 하는 규칙, 세부 사항 및 지침을 제공한다.JavaScript
는 ECMAScript
사양을 준수하는 범용 스크립팅 언어이다.Ecam 인터네셔널
(정보 통신에 대한 표준을 제정하는 비영리 표준화 기구) >
ECMA-262
(범용 목적의 스크립트 언어에 대한 명세) >
ECMAScript
(ECMA-262 기술 규격에 의해 정의된 범용 스크립트 언어, 스크립트 언어가 준수해야 하는 규칙과 세부 사항 및 지침 제공) >
JavaScript
(ECMAScript 사양을 준수하는 범용 스크립팅 언어)
JavaScript 엔진
에는 여러 종류가 있다. Google Chrome의 V8
, Mozilla Firefox의 SpiderMonkey
, Microsoft Edge의 Chakra
등이 있는데 각각의 엔진은 모두 수행능력이 차이가 나고 무엇보다도 지원되는 ECMAScript
가 다르다. 엔진을 고려하지 않고 ES6 코드를 사용하게 될 경우 오류가 발생할 수 있다. 따라서 컴파일 단계를 거쳐서 ES6
코드를 ES5
로 변환시켜 엔진을 돌려야 하는 일이 생길 수 있는데 이때 사용하는것이 Babel
이다.
[1].includes(1); // true
2**10 // 1024
async getData() {
const res = await api.getTableData(); // await asynchronous task
// do something
}
Object.values({a: 1, b: 2, c: 3}); // [1, 2, 3]
Object.entries({a: 1, b: 2, c: 3}); // [["a", 1], ["b", 2], ["c", 3]]
개체의 모든 속성에 대한 설명자를 가져오거나 개체의 속성이 없는 경우 빈 개체를 반환.
let user = { name: "John"};
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
console.log(JSON.stringify(descriptor, null, 2));
/* property descriptor:
{
"value": "John",
"writable": true,
"enumerable": true,
"configurable": true
}
*/
멀티 스레드간에 메모리 공유를 위해 사용. 주요 브라우저에서 기본적으로 비활성화 되어있음.
/**
** @param {*} length The size of the array buffer created, in bytes.
** @Returns {ShareDarrayBuffer} A new ShareDarrayBuffer object of specified size. Its contents are initialized to 0. */
new SharedArrayBuffer(10)
MDN SharedArrayBuffer
만화로 소개하는 ArrayBuffer 와 SharedArrayBuffer
Atomics 개체는 ShareDarrayBuffer 개체에서 원자적 작업을 수행하는 데 사용되는 정적 메서드 집합을 제공함.
문자열 끝 부분이나 시작 부분을 다른 문자열로 채워 주어진 길이를 만족하는 새로운 문자열을 만들어낼 수 있다.
"hello".padStart(6); // " hello"
"hello".padEnd(6); // "hello "
"hello".padStart(3); // "hello" // 문자열 길이보다 목표 문자열 길이가 짧다면 채워넣지 않고 그대로 반환
"hello".padEnd(20, "*"); // "hello***************" // 사용자가 지정한 값으로 채우는 것도 가능
JavaScript는 초기부터 배열 리터럴에 trailing comma를 허용했으며, ECMAScript 5부터는 객체 리터럴, ECMAScript 2017부터는 함수의 매개변수에도 허용
function f(p) {}
function f(p,) {}
(p) => {};
(p,) => {};
async function process(array) {
for await (let i of array) {
// doSomething(i);
}
}
Promise가 처리되면 충족되거나 거부되는지 여부에 관계없이 지정된 콜백 함수가 실행됨.
Promise.resolve().then().catch(e => e).finally();
const myObj = { a: 1, b: 3, c: 'cc', d: 100 };
const {a, b, ...z} = myObj;
console.log(z); // { "c": "cc", "d": 100 }
const spread = { ...myObj, a: 10, e: 30,};
console.log(spread); // { "a": 10, "b": 3, "c": "cc", "d": 100, "e": 0 }
앞에 오는 항목에 따라 문자열 일치
// ?= 특정 하위 문자열이 뒤에 오는 문자열을 일치시키는데 사용
/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
// ASCII
/^\p{ASCII}+$/u.test('abc') //✅
/^\p{ASCII}+$/u.test('ABC@') //✅
/^\p{ASCII}+$/u.test('ABC🙃') //❌
// HEX
/^\p{ASCII_Hex_Digit}+$/u.test('0123456789ABCDEF') //✅
/^\p{ASCII_Hex_Digit}+$/u.test('h') //❌
// Emoji, ppercase, Lowercase, White_Space, Alphabetic
/^\p{Lowercase}$/u.test('h') //✅
/^\p{Uppercase}$/u.test('H') //✅
/^\p{Emoji}+$/u.test('H') //❌
/^\p{Emoji}+$/u.test('🙃🙃') //✅
// Script
/^\p{Script=Greek}+$/u.test('ελληνικά') //✅
/^\p{Script=Latin}+$/u.test('hey') //✅
ES2018에서는 결과 배열의 슬롯을 할당하는 대신 캡처 그룹을 이름에 할당할 수 있음
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';
.표현식은 개행문자를 제외한 모든 문자였으나, s플래그를 달면 개행식도 포함하게 된다.
/hi.welcome/.test('hi\nwelcome') // false
/hi.welcome/s.test('hi\nwelcome') // true
// 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"]
try {
//...
} catch /*(e)*/ {
//handle error
}
const entries = new Map([
['foo', 'bar'],
['baz', 42]
]);
const obj = Object.fromEntries(entries);
console.log(obj);
// expected output: Object { foo: "bar", baz: 42 }
// 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'
심벌 객체의 description은 해당 심벌 객체의 설명을 반환한다.
Symbol('desc').toString(); // "Symbol(desc)"
Symbol('desc').description; // "desc"
이 변경 이전에는 JSON 으로 구문 분석된 문자열에서 줄 구분 기호(\u2028) 및 단락 구분 기호(\u2029)가 허용되지 않았다. 이제 JSON.parse()를 사용하면 해당 문자 SyntaxError가 JSON 표준에 정의된 대로 올바르게 구문 분석된다.
잘못된 형식의 유니코드 문자열을 반환하지 않도록 JSON.stringify를 변경되었다.
JSON.stringify("\uD800"); // 변경 전 --> '"�"' // 잘못된 형식의 유니코드 문자를 반환
JSON.stringify("\uD800"); // 변경 후 --> '"\ud800"' // 유효한 유니코드를 반환
toString() 메서드는 함수의 소스 코드를 나타내는 문자열을 반환한다. ES2016까지는 소스 코드에서 주석이나 공백 문자를 제거했지만, ES2019에서 개정되어 문자열에 주석 등도 포함된다.
function /* this is bar */ bar() {}
// old
bar.toString() //'function bar() {}
// new
bar.toString() // 'function /* this is bar */ bar () {}'
BigInt는 정수 리터럴의 뒤에 n을 붙이거나(10n) 함수 BigInt()를 호출해 생성할 수 있다.
BigInt와 Number는 어떤 면에서 비슷하지만 중요한 차이점이 있습니다. 예컨대 BigInt는 내장 Math객체의 메서드와 함께 사용할 수 없고, 연산에서 Number와 혼합해 사용할 수 없습니다. 따라서 먼저 같은 자료형으로 변환해야 합니다. 그러나, BigInt가 Number로 바뀌면 정확성을 잃을 수 있으니 주의해야 합니다. 또한 bigDecimal이 아니기 때문에 소수점 이하는 언제나 버립니다.
const theBiggestInt = 9007199254740991n;
const bigintSum = theBiggestInt + 1n; // 9007199254740992n
const alsoHuge = BigInt(9007199254740991); // 9007199254740991n
typeof bigintSum // "bigint"
ES2020 부터는 필요할 때 모듈을 동적으로 가져올 수 있다.
if (condition1 && condition2) {
const module = await import('./path/to/module.js');
module.doSomething();
}
?. 연산자는 . 체이닝 연산자와 유사하게 작동하지만, 만약 참조가 nullish(null 또는 undefined)이라면, 에러가 발생하는 것 대신에 표현식의 리턴 값은 undefined로 단락된다. 함수 호출에서 사용될 때, 만약 주어진 함수가 존재하지 않는다면, undefined를 리턴한다.
const adventurer = {
name: 'Alice',
cat: { name: 'Dinah' }
};
const catName = adventurer.cat?.name; // 'Dinah'
const dogName = adventurer.dog?.name; // undefined
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"
}
]
널 병합 연산자 (??) 는 왼쪽 피연산자가 null 또는 undefined일 때 오른쪽 피연산자를 반환하고, 그렇지 않으면 왼쪽 피연산자를 반환하는 논리 연산자이다.
let user = { u1: 0, u2: false, u3: null, u4: undefined u5: '', }
let u1 = user.u1 ?? 'user 1' // 0
let u2 = user.u2 ?? 'user 2' // false
let u3 = user.u3?? 'user 3' // user 3
let u4 = user.u4?? 'user 4' // user 4
let u5 = user.u5?? 'User 5' // ''
matchAll 메서드는 지정된 정규식에 대해 문자열과 일치하는 모든 결과의 iterator를 반환하는 메서드입니다.(캡쳐링 그룹 포함) 정규 표현식 뒤에 g flag를 사용해주어야 합니다.
const regexp = /t(e)(st(\d?))/g;
const str = 'test1test2';
const array = [...str.matchAll(regexp)];
console.log(array[0]); // expected output: Array ["test1", "e", "st1", "1"]
console.log(array[1]); // expected output: Array ["test2", "e", "st2", "2"]
export * as A from "./moduleA";
export * as B from "./moduleA";
import { A, B } from "./modules";
console.log(A.a); // 1
console.log(A.b); // 2
console.log(B.b); // 3
console.log(B.c); // 4
현재 모듈파일의 메타정보를 가져올 수 있다.
<script type="module" src="my-module.js">
console.log(import.meta); // { url: "file:///home/user/my-module.js" }
globalThis는 환경에 관계없이 전역객체를 통일된 방법으로 참조할 수 있는 방법이다.
// browser environment
console.log(globalThis); // => Window {...}
// node.js environment
console.log(globalThis); // => Object [global] {...}
// web worker environment
console.log(globalThis); // => DedicatedWorkerGlobalScope {...}
정규식에 g옵션을 통해 전역으로 적용하지 않고도 문자열의 지정한 모든 문자열을 특정 문자열의 값으로 변경한다.
const str = 'hello world';
str.replaceAll('l', ''); // "heo word"
Promise 반복 가능 객체를 수신하고 Promise 중 하나가 성공할 때마다 성공한 Promise를 반환한다. iterable 객체의 Promise 중 어느 것도 성공하지 못하면(즉, 모든 Promise가 실패/거부됨) 실패한 Promise가 반환된다.
const anySuccessPromises = [
new Promise((res, rej) => setTimeout(res, 200, 'first')),
new Promise((res, rej) => setTimeout(rej, 100, 'second')),
new Promise((res, rej) => setTimeout(res, 300, 'third')),
];
// first
Promise.any(anySuccessPromises)
.then(value => console.log(value))
.catch(error => console.error(error));
const allFailurePromises = [
new Promise((res, rej) => setTimeout(rej, 100, 'first')),
new Promise((res, rej) => setTimeout(rej, 200, 'second')),
new Promise((res, rej) => setTimeout(rej, 300, 'third')),
];
// AggregateError: All promises were rejected
Promise.any(anySuccessPromises)
.then(value => console.log(value))
.catch(error => console.error(error));
WeakRef개체를 사용하면 해당 개체가 가비지 수집되는 것을 방지하지 않고 다른 개체에 대한 약한 참조를 유지할 수 있다.
class Counter {
constructor(element) {
// Remember a weak reference to the DOM element
this.ref = new WeakRef(element);
this.start();
}
start() {
if (this.timer) {
return;
}
this.count = 0;
const tick = () => {
// Get the element from the weak reference, if it still exists
const element = this.ref.deref();
if (element) {
element.textContent = ++this.count;
} else {
// The element doesn't exist anymore
console.log("The element is gone.");
this.stop();
this.ref = null;
}
};
tick();
this.timer = setInterval(tick, 1000);
}
stop() {
if (this.timer) {
clearInterval(this.timer);
this.timer = 0;
}
}
}
const counter = new Counter(document.getElementById("counter"));
setTimeout(() => {
document.getElementById("counter").remove();
}, 5000);
// before
obj.prop = obj.prop || foo(); // obj.prop이 잘못된 값일 경우 할당
obj.prop = obj.prop && foo(); // obj.prop이 올바른 값일 경우 할당
obj.prop = obj.prop ?? foo(); // obj.prop이 null이나 undefined일 경우 할당
// after
obj.prop ||= foo();
obj.prop &&= foo();
obj.prop ??= foo();
// before
10000000000 // 100억
// after
10_000_000_000 // 100억
console.log(10_000_000_000); // 10000000000
sort는 implementation-defined로 기본적인 스펙만 제공하고 나머지는 브라우저에게 맡겼기 때문에 브라우저마다 구현이 달라서 정렬 결과가 다른 문제가 있었다. 이 스펙을 좀 더 정교하게 정의해서 브라우저마다 다를 수 있는 경우의 수를 줄였다.
ES2022는 2022년 6월에 출시되며 2022년 3월까지 4단계에 도달한 모든 아이디어는 JavaScript에 포함될 예정이다.
이전에는 비동기 함수 외부에서 await 키워드를 선언할 수 없어 오류가 발생했다. 이제 비동기 함수 및 클래스 외부에서 await 연산자를 선언하여 동기화 문제를 해결할 수 있다.
import {getUser} from "./data/User"
let user = await getUser();
처음에는 생성자 내에서만 클래스 필드를 선언할 수 있었지만 이제는 4단계의 제안을 사용하여 생성자를 호출할 필요없이 클래스 자체에서 선언할 수 있다.
class hello {
fields = 0;
title;
}
#
기호를 접두사로 사용하여 private 클래스 필드를 직접 선언할 수 있다. 동일한 기호를 사용하여 메서드와 접근자를 비공개로 설정할 수 있으며 동시에 getter 및 setter 메서드를 사용할 수도 있다.
class hello {
fields = 0;
#title;
get #title() { return #title; }
set #title() { #title = null; }
}
static 키워드를 사용하여 정적 클래스 필드와 개인 정적 메서드를 선언하는 방법을 제공
class hello {
name;
static title = 'here';
static get title() { return title; }
}
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";
in 연산자를 사용하여 특정 클래스에 필드가 있는지 여부를 간단히 확인할 수 있다.
class hello{
name;
#title;
get #title() {
return #title;
}
set #title() {
#title=null;
}
static hasTitle(obj1) {
return #title in obj1;
}
}
at() 함수를 사용하여 양수 및 음수 인덱스를 모두 사용하여 문자열을 인덱싱할 수 있다.
array= [1.2.4.5]
console.log(array[array.length-1]);
console.log(array.at(-1));
Object.prototype.hasOwnProperty.call()과 동일한 hasOwn() 추가
const obj1={ hello:'Hi' }
let hasHello1=Object.prototype.hasOwnProperty.call(obj1, 'hello');
let hasHello= obj1.hasOwn(obj1, 'hello'); //
console.log(hasHello);
console.log(hasHello1);
Temporal은 ECMAScript 언어에 최신 날짜/시간 API를 제공하는 최상위 네임스페이스 역할을 하는 전역 개체 제공
이 함수를 사용하면 조건에 따라 배열의 마지막 요소부터 첫 번째 요소까지 찾을 수 있습니다.
const array = [{a: 1, b: 1}, {a: 2, b: 2}, {a: 3, b: 3}, {a: 4, b: 4}]
console.log(array.findLast(n => n)); //result -> {a: 4,b: 4 }
console.log(array.findLast(n => n.a * 5 === 20)); // result -> {a:4,b:4} as the condition is true so it returns the last element.
console.log(array.findLast(n => n.a * 5 === 21)); //result -> undefined as the condition is false so return undefined instead of {a:4,b:4}.
console.log(array.findLastIndex(n => n.a * 5 === 21)); // result -> -1 as the condition is not justified for returning the last element.
console.log(array.findLastIndex(n => n.a * 5 === 20)); // result -> 3 which is the index of the last element as the condition is true.
이 기능을 사용하면 일부 CLI에서 해시방/셰방을 사용할 수 있습니다. Shebang은 #! 로 표시되며 스크립트 시작 부분에 있는 특수 줄로, 스크립트를 실행할 때 어떤 인터프리터를 사용할지 운영 체제에 알려주는 역할을 합니다.
#!/usr/bin/env node
// in the Script Goal
'use strict';
console.log(2*3);
#!/usr/bin/env node
// in the Module Goal
export {};
console.log(2*2);
#!/usr/bin/env 노드 이 줄은 Node.js 소스 파일을 자체적으로 실행 파일로 직접 호출합니다. 노드 인터프리터를 통해 명시적으로 파일을 호출하려면 #!/usr/bin/env node가 필요하지 않습니다(예: node ./file).
이를 통해 고유한 심볼을 키로 사용할 수 있습니다. 현재 위크맵은 객체만 키로 허용하도록 제한되어 있습니다. 객체가 위크맵의 키로 사용되는 이유는 객체와 위크맵이 동일한 아이덴티티 측면을 공유하기 때문입니다. Symbol은 ECMAScript에서 유일하게 고유한 값을 허용하는 기본 유형이므로 WeakMap으로 새 객체를 생성하는 대신 Symbol을 키로 사용할 수 있습니다.
const weak = new WeakMap();
const key = Symbol('my ref');
const someObject = { a:1 };
weak.set(key, someObject);
console.log(weak.get(key));
원래 배열을 업데이트하는 대신 변경 사항과 함께 새 복사본을 반환하여 배열을 변경할 수 있는 추가 메서드가 Array.prototype에 제공됩니다.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
/* toReversed */
const reversed = numbers.toReversed();
console.log("reversed", reversed); // "reversed", [9, 8, 7, 6, 5, 4, 3, 2, 1]
console.log("original", numbers); // "original", [1, 2, 3, 4, 5, 6, 7, 8, 9]
/* toSorted */
const sortedArr = numbers.toSorted();
console.log("sorted", sortedArr); // "sorted", [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log("original", numbers); // "original", [1, 2, 3, 4, 5, 6, 7, 8, 9]
/* with */
const replaceWith = numbers.with(1, 100);
console.log("with", replaceWith); // "with", [1, 100, 3, 4, 5, 6, 7, 8, 9]
console.log("original", numbers); // "original", [1, 2, 3, 4, 5, 6, 7, 8, 9]
/* toSpliced */
const splicedArr = numbers.toSpliced(0, 4);
console.log("toSpliced", splicedArr); // "toSpliced", [5, 6, 7, 8, 9]
console.log("original", numbers); // "original", [1, 2, 3, 4, 5, 6, 7, 8, 9]
https://velog.io/@kyusung/after-es6
https://wormwlrm.github.io/2018/10/03/What-is-the-difference-between-javascript-and-ecmascript.html
https://dev.to/jasmin/what-is-new-in-es2023-4bcm