본문 바로가기

Backend/Javascript

ES9 (ES2018)

이번 포스팅에선 ES9 의 기능들에 대해 알아보겠습니다. 나온진 꽤 됐지만 쓰는 기능도 있고 처음 보는 기능 (관심이 부족했는지..) 도 있어 적어보려 합니다.

 

- Object rest/spread properties

 

ES6 때부터 spread operator 와 rest parameters 는 도입이 되었었습니다. 먼저 이 두 문법부터 간단히 보도록 하겠습니다.

 

const list1 = [1, 2, 3];
const list2 = [...list1, 4, 5, 6];

console.info(list2); // [1, 2, 3, 4, 5, 6]

 

위는 spread operator 의 예시입니다. 전개 연산자라고도 하는데 이름 그대로 Iterable 한 배열의 프로퍼티를 펼치는 역할을 합니다. 단순 펼치는게 아니라 복사해 새로운 배열을 만들어내죠.

 

const list1 = [1, 2, 3, 4, 5, 6];
const [one, ...rest] = list1;

console.info(one); // 1
console.info(rest); // [2, 3, 4, 5, 6]

 

이번엔 rest parameters 의 예시입니다. 이것 또한 말 그대로 변수로 할당한 부분을 제외한 나머지 프로퍼티들을 합쳐서 하나로 받을 수 있는 문법입니다.

 

ES9 에 추가된 Object rest/spread properties 라는 기능은 위의 기능을 배열이 아닌 객체에서도 쓸 수 있게 된 것 입니다.

 

const test1 = { id1: 1 };
const test2 = { ...test1, id2: 2 };
const test3 = { ...test2, id3: 3 };

console.info(test1); // { id1: 1 }
console.info(test2); // { id1: 1, id2: 2 }
console.info(test3); // { id1: 1, id2: 2, id3: 3 }

const test4 = { id1: 1, id2: 2, id3: 3 };
const { id1, ...rest } = test4;

console.info(id1); // 1
console.info(rest); // { id2: 2, id3: 3 }

 

배열에서 많이 써왔던 기능이고, 지금은 object destructuring 또한 너무 흔하게 사용하기 때문에 눈에 아주 익숙한 문법들입니다.

이런 기능들을 통해 객체를 복사할 때 Object.assign 을 따로 사용하지 않아도 되고, JS 에서 가변인자를 받는 함수를 처리할 손쉽게 만들고 다룰 수 있게 되었습니다. 물론 그전에도 할 수 없었던 건 아니지만, 여러모로 편해진 ... syntax 입니다.

 

-AsyncIterator 

 

JS 에서 Iterable 하다는 것은 Symbol.Iterator 가 구현되어 있는 객체이고, 이러한 객체는 Iterator 의 next 메서드를 통해 Iterable 한 객체의 다음 값에 접근할 수 있게 됩니다. 이 값은 실제로 value 와 done 으로 구분됩니다.

 

const list1 = [1, 2, 3];
const iterator = list1[Symbol.iterator]();

const test1 = iterator.next();
console.info(test1); // { value: 1, done: false }
const test2 = iterator.next();
console.info(test2); // { value: 2, done: false }
const test3 = iterator.next();
console.info(test3); // { value: 3, done: false }
const test4 = iterator.next();
console.info(test4); // { value: undefined, done: true }
const test5 = iterator.next();
console.info(test5); // { value: undefined, done: true }

 

위는 기존 Iterator 에 대한 간단한 예시입니다. list1 배열을 강제로 Iterator 로 만들어 next 를 호출했을 때, 각각 value 1 2 3 에 순차적으로 접근하고 그때까진 done 의 상태가 끝나지 않았으므로 false 를 반환하다가 전부 끝나면 true 로 변하죠. 이미 끝난 iterator 에선 next 를 계속 호출해도 undefined value 를 반환하는 것을 볼 수 있습니다.

 

하지만 이 Iterator 는 동기식에만 적용 가능했고, 비동기식에는 적용되지 않았습니다. (물론 제네레이터가 있긴 합니다만..)

ES9 에서 소개되는 AsyncIterator 는 이제 이 Iterator 를 비동기식에도 적용할 수 있게 된 것입니다.

 

const test1 = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      console.info('test1');
      resolve(1);
    }, 1000);
  });
};

const test2 = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      console.info('test2');
      resolve(2);
    }, 3000);
  });
};

const test3 = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      console.info('test3');
      resolve(3);
    }, 500);
  });
};

(async () => {
  const promises = [test1(), test2(), test3()];

  for await (const item of promises) {
    console.info(item);
    // 1, 2, 3
    // 하지만 내부 console.info 는 test3, test1, test2
  }
})();

 

for await 문법을 제공함으로써 위와 같이 다음 값에 접근할 때마다 반환되는 promise 에 암시적으로 await 가 적용됩니다.

 

- Promise.prototype.finally

 

const test1 = (id) => {
  return new Promise((resolve, reject) => {
    if (id < 10) {
      resolve('ok');
    } else {
      reject('error');
    }
  });
};

test1(3).then(result => {
  console.info(result); // 'ok'
}).catch (err => {
  console.error(err);
}).finally(() => {
  console.info('finally'); // 'finally'
});

test1(11).then(result => {
  console.info(result);
}).catch (err => {
  console.error(err); // 'error'
}).finally(() => {
  console.info('finally'); // 'finally'
});

 

새로이 추가된 Promise.prototype.finally 메서드에서는 Promise 가 resolve 혹은 reject 되는지와는 상관없이 무조건 지정된 콜백 함수가 호출됩니다. 위 예시는 좀 발로 만들긴했는데.. 두 케이스 모두 finally 가 호출되는 것을 볼 수 있습니다.

try - catch 문에서의 finally 와 유사하고, promise 가 처리된 이후 무조건 한번 실행되기에 할당한 리소스나 커넥션등을 처리할 때 유용하게 사용할 수 있을 것 같습니다.

 

- 정규표현식 dotAll Flag

 

console.info(/foo.bar/.test('foo\nbar')); // false
console.info(/foo.bar/s.test('foo\nbar')); // true

 

정규표현식에 새롭게 추가된 s flag (dotAll) 입니다.

원래 . 표현식 에선 개행문자를 제외한 모든 문자였지만, s flag 를 달면 개행문자도 포함하게 됩니다.

정규표현식에는 이 외에도 named capture groups, unicode property escapes, look-behind assertion 등이 추가되었지만
원체 이쪽은 잘 안쓰다보니 dotAll flag 정도만 보고 넘어가도록 하겠습니다.

'Backend > Javascript' 카테고리의 다른 글

ES11 (ES2020)  (0) 2022.03.05
ES10 (ES2019)  (0) 2022.02.27
ECMAScript  (0) 2022.02.12
TC39 Process  (0) 2022.02.07
ES2022  (0) 2022.01.30