안녕하세요. 이번 시간에는 stage-3에 이어 stage-2에 대해 알아보겠습니다! 1~3년 내에 정식 스펙에 들어갈 만한 친구들입니다.
여기에 따르면 아직 브라우저에서 지원하는 것이 없습니다. @babel/preset-stage-2나 typescript를 설치하면 이 기능들을 사용할 수 있습니다. class decorators는 정말 놀라운 변화입니다.
다음 코드는 브라우저에서 동작하지 않으니 따라 치지는 마시고 눈으로만 보세요.
class decorators
리액트를 하셨던 분이라면 몇 번 보셨을텐데요. 클래스를 감싸는 함수를 만드는 방법입니다. HOC를 만들 때 가끔 이런 문법을 쓰는 것을 보신 적이 있을 겁니다.
function hello(msg) {
return function(target) {
target.hello = msg;
};
}
function readonly(target, key, descriptor) {
descriptor.writable = false;
return descriptor;
}
@hello('안녕')
class ZeroCho {
@readonly
static name = 'zerocho';
}
ZeroCho.hello; // '안녕'
ZeroCho.name; // 'zerocho';
ZeroCho.name = 'babo'; // Error 발생
클래스와 속성 앞에 @로 시작하는 함수가 붙었죠? 이것들이 decorator입니다. 다음 줄에 나오는 클래스나 속성이 target으로 들어가고요. hello 함수를 보면 '안녕'이라는 글자를 받아서 target.hello에 그 글자를 대입합니다. 여기서의 target은 @hello 다음에 나오는 ZeroCho 클래스입니다.
readonly 함수를 보면 다음에 나오는 속성의 descriptor를 받아 writable을 false로 만들어주었습니다. 따라서 @readonly decorator 다음에 나오는 name 속성은 수정할 수 없습니다. 여기서의 target은 name 속성이 됩니다. descriptor은 name 속성의 descriptor인 것이고요.
function.sent
generator에서 function.sent 특수값을 사용할 수 있습니다. next의 인수로 전달된 값을 function.sent로 받는 것입니다.
var result;
function* generator() {
result = function.sent;
}
var iter = generator();
iter.next('tromple');
result === 'tromple'; // true
throw expressions
throw를 자유자재로 할 수 있습니다. 신나게 에러를 뱉어봅시다. 함수의 인자를 검사하거나 할 때 유용하게 쓸 수 있습니다.
a = a || throw 'a는 필수 인자입니다';
b = b && throw 'b는 거짓(falsy) 값이어야 합니다.'
function(c = throw 'c는 필수 인자입니다') { }
d = () => throw '무조건 에러'
e = e ? true : throw 'e는 참(truthy) 값이어야 합니다.'
물론 throw의 인자는 catch의 error로 전달됩니다.
Set methods
Set에 intersection(교집합), union(합집합), difference(차집합), symmetricDifference(대칭차집합), isDisjointFrom(교집합없음), isSubsetOf(부분집합), isSupersetOf(상위집합) 등 집합을 적용할 수 있는 개념들이 추가되었습니다. 매우 편하게 두 배열을 비교할 수 있게 되었습니다. 아래는 전부 true입니다.
var set = new Set([1, 2, 3]).intersection(new Set([2, 3, 4]));
set.size === 2 && set.has(2) && set.has(3);
var set = new Set([1, 2]).union(new Set([2, 3]));
set.size === 3 && set.has(1) && set.has(2) && set.has(3);
var set = new Set([1, 2, 3]).difference(new Set([3, 4]));
set.size === 2 && set.has(1) && set.has(2);
var set = new Set([1, 2]).symmetricDifference(new Set([2, 3]));
set.size === 2 && set.has(1) && set.has(3);
new Set([1, 2, 3]).isDisjointFrom([4, 5, 6]);
new Set([1, 2, 3]).isSubsetOf([5, 4, 3, 2, 1]);
new Set([5, 4, 3, 2, 1]).isSupersetOf([1, 2, 3])
Map.prototype.upsert
Map에 새로운 값을 추가하거나, 이미 존재하는 경우 새 값으로 수정하는 메서드인 upsert가 추가되었습니다. 아래 예시에서 a는 존재하므로 값이 2로 바뀌고 b는 존재하지 않으므로 값이 3으로 추가됩니다. 두 번째와 세 번째 인수인 함수는 각각 존재하면 2로 바꾸고, 존재하지 않으면 3으로 하라는 뜻입니다
const map = new Map([['a', 1]]);
map.upsert('a', it => 2, () => 3) === 2;
map.upsert('b', it => 2, () => 3) === 3;
Array.from(map).join() === 'a,2,b,3';
Array.isTemplateObject
템플릿 문자열 함수를 통해 생성된 배열인지를 알려주는 메서드입니다.
!Array.isTemplateObject([]) // true
Array.isTemplateObject((it => it)`a${1}c`); // true
Iterator Helpers
반복되는 값을 나타내는 Iterators에 여러 메서드가 추가됩니다. 배열.values()를 하면 Iterator 객체가 나오는데 여기에 배열 메서드들이 대다수 추가된다고 보시면 됩니다.
Record & Tuple
Record와 Tuple이 추가됩니다. 근래의 가장 큰 변화입니다.
const proposal = #{
id: 1234,
title: "Record & Tuple proposal",
contents: `...`,
// tuples are primitive types so you can put them in records:
keywords: #["ecma", "tc39", "proposal", "record", "tuple"],
};
// Accessing keys like you would with objects!
console.log(proposal.title); // Record & Tuple proposal
console.log(proposal.keywords[1]); // tc39
// Spread like objects!
const proposal2 = #{
...proposal,
title: "Stage 2: Record & Tuple",
};
console.log(proposal2.title); // Stage 2: Record & Tuple
console.log(proposal2.keywords[1]); // tc39
// Object functions work on Records:
console.log(Object.keys(proposal)); // ["contents", "id", "keywords", "title"]
const ship1 = #{ x: 1, y: 2 };
// ship2 is an ordinary object:
const ship2 = { x: -1, y: 3 };
function move(start, deltaX, deltaY) {
// we always return a record after moving
return #{
x: start.x + deltaX,
y: start.y + deltaY,
};
}
const ship1Moved = move(ship1, 1, 0);
// passing an ordinary object to move() still works:
const ship2Moved = move(ship2, 3, -1);
console.log(ship1Moved === ship2Moved); // true
// ship1 and ship2 have the same coordinates after moving
자바스크립트의 Map, Set, Iterator에 점점 기능이 붙기 시작하네요. 다음 시간에는 stage-1에 대해서 알아보겠습니다!