ES6 요약

yb·2021년 5월 21일
0

WEB

목록 보기
2/3
post-thumbnail

ES6

ES6ECMA에서 2015년에 채택한 자바스크립트 표준이다.
때문에 ECMA2015라고도 할 수 있다.

ES6 , ES2015, ECMA2015 다 같은 말이다.

ECMA는 정보통신기술(ICT), 전자제품(CE)를 위한 국제 표준 기구이다.

[let, const]

기존 [var] 키워드의 문제점

정의된 변수가 함수 스코프를 가진다.

function foo() {
  var i = 1;
}
console.log(i); //Uncaught ReferenceError: i is not defined

때문에 아래와 같은 같은 문제를 야기할 수 있다.

  • var 미 선언시 전역 변수가 된다.
function foo() {
  i = 1;
}
function bar() {
  console.log(i);
}
foo();
bar(); // 1 출력!
  • for문을 벗어나도 변수가 사라지지 않는다.
for (var i =0; i< 10; i ++) {
  console.log(i);
}

console.log(i); // 10

ES5에서는 이러한 문제를 해결하기 위해 즉시실행함수를 통해 변수의 스코프를 제한할 수 있었다.

호이스팅

호이스팅이란, var키워드를 통해 정의된 변수는 그 변수가 속한 스코프의 최상단으로 올라온다.

이해 예시

1번

console.log(foo); // Uncaught ReferenceError: foo is not defined

2번

console.log(foo); // undefined
var foo = 1;

2번 - 실제 동작

var foo = undefined;
console.log(foo);
foo = 1;

3번 변수 정의 이전에 값 할당

function foo() {
  bar = 2;
  console.log(bar); // 2
  var bar = 1;
}
foo();
console.log(bar); // Uncaught ReferenceError: bar is not defined

[const, let]은 블록 스코프이다.

if(true) {
  const foo = 1;
}
console.log(foo); // Uncaught ReferenceError: foo is not defined
let foo = 1;
console.log(foo); // 1
if (true) {
  let foo = 2;
  console.log(foo); // 2
}
console.log(foo); // 1

[const,let] 호이스팅

console.log(foo); // Uncaught ReferenceError: Cannot access 'foo' before initialization
const foo = 1;

const, let 또한 호이스팅을 지원하지만 var키워드와는 다르게 참조 에러가 발생한다.
다만, 정의된 위치와 호이스팅된 위치 사이에서 변수를 참조시, 에러가 발생한다.
이러한 구간을 임시적 사각지대(temporal dead zone)이라고도 한다.

let foo = 1;
{
  // 이해를 돕기위해 ++  호이스팅이 되지않았다면 1을 정상적으로 출력했어야함.
  console.log(foo); // Uncaught ReferenceError: Cannot access 'foo' before initialization
  let foo = 2;
}

[const] 재할당 불가능

const foo = 1;
foo = 2; // Uncaught TypeError: Assignment to constant variable.

하지만 const로 정의해도 객체 내부 속성값은 수정이 가능하다.

// Object
const foo = {
 age: 1,
 name: 'Park',
};
foo.age = 5;
console.log(foo.age); // 5

// Array
const foo = [1,2,3];
foo[0] = 0;
foo.push(100);
console.log(foo); // [0,2,3,100]

전개 연산자와 비구조화 할당(destructuring assignment)

단축 속성명

const name = 'Park';
const person = {
  age: 10,
  name,
  getName() {return this.name}
}

계산된 속성명

const key = 'age';
const value = 12;
const obj = { [key]: value }; // {age: 12}

전개 연산자

// 전개 연사자 미사용
Math.max(1, 2, 3, 4);

// 전개 연산자 사용시
const nums = [1,2,3,4];
Math.max(...nums);

// 예제
const nums2 = [...nums, 5, 6]; // [1,2,3,4,5,6]
const nums3 = [1, 2, ...[3,4], 5, 6] // [1,2,3,4,5,6] 순서 유지됨
const obj = { 'age': 1 };
const person = {
  ...obj,
  'name': 'Park'
} // { 'age': 1, 'name': 'Park' }


const person2 = {
  ...person,
  'name': 'Kim'
} // { ''age : 1, 'name': 'Kim'}

비구조화

배열에서 변수 할당

const arr = [1, 2];
const [a,b] = arr; //
console.log(a); // 1
console.log(b); // 2

// 아래와 같이 사용할 수 도 있다
let a,b;
[a,b] = [1,2]; // [1,2]
[a, b] = [b, a]; // [2,1]

// 할당을 원치 않는 값
const [a,,c] = [1,2,3]; // a = 1, c = 3

객체에서 변수 할당

const obj = { a: 1, b:2 };
const {a, b} = obj; // a = 1, b = 2
// 키값을 통해 할당된다.
const {b, a} = obj; // a = 1, b = 2

// 별칭 사용시
const {a:foo, b} = obj; // foo = 1, b = 2

function bar({a,b}) {
   console.log(a+b);
}

bar({1,2}); // 3출력

함수를 사용하여 기본값을 설정할 수도 있다.

const getNum = () => 1;
const {num = getNum(), name} = {name: 'kim'};
// num = 1, name = 'kim'

함수(function)

매개변수 기본값

function foo(a=1) {
  console.log(a);
}
function foo(a=bar()) {
  // 함수도 가능하다
  console.log(a)
}

foo(); // 1

이를 이용하여 필수값 체크하는 방법

function required() {
  throw new Error('no parameter');
}

function foo(a = required()) {
  console.log(a);
}

foo(); // error! no parameter!

나머지 매개변수

function foo (a, ...rest) {
  console.log({a, rest});
}
foo(1,2,3); // {a: 1, rest: [2,3]}

화살표 함수(Arrow Functions)

const add = (a,b)=> a+b;
console.log(add(1,3)); // 4
const add3 = a => a + 3;
console.log(add3(1)); // 4
const returnObj = (a,b) => ({rs: a+b}); // object 반환시 소괄호 사용
console.log(returnObj(1,3).rs); // 4

// 두줄이상 작성시 중괄호 사용 필요
const arrow = () => {
  console.log('2줄 이상 작성시');
  return 'some..';
}

화살표 함수 사용 시 주의할 점

  • 화살표 함수로 생성된 함수는 this를 가지지 않는다.
    (this를 바인딩하지 않고 상위 scope의 this를 가르킨다)
  • 메소드,prototype,생성자함수,addEventListener 콜백함수로 부적절하다.
  • arguments 프로퍼티가 없기 때문에 rest 파라미터를 사용해야 한다.

비동기 프로그래밍

Promise

서론

기존 비동기 프로그래밍 방식으로 callback패턴을 많이 사용하였다.
콜백지옥이라는 말이 나올정도로 중첩되면 복잡해지기 쉬운 구조이다.
하지만, Promise에서는 순차적으로 실행되도록 작성이 가능하다!

예시

req_01()
  .then(data => {
    console.log(data);
    return req_02();
  })
  .then(data => {
    console.log(data);
    // ...
  })

생성 방법

const p1 = new Promise((resolve, reject) => {
  // ...
  // resolve(data);
  // reject('error');
});

const p2 = Promise.reject('error');
const p3 = Promise.resolve(param);

병렬 처리

// p1, p2 Promise 객체
Promise.all([req_01(), req_02()]).then((data1, data2) => {
  console.log(data1, data2)
})
/*
Promise.all은 모든 프로미스가 정상적으로 처리될 경우에만 then 을 실행,
하나만 실패하더라도 reject로 실패처리된다.
*/

async, await

async, await함수는 Promise를 반환합니다.
함수간의 의존성이 높은 경우 가독성이 훨씬 높다.

Promise는 객체, async, await는 함수 이다

async function req() {
  retrun 123;
}
req().then(data => console.log(data)); // 123

예시

// req_1, req_2 는 프로미스 객체를 리턴하는 함수이다.
async function getData() {
  const data1 = await req_1();
  const data2 = await req_2(data1);
  console.log(data1, data2);
}

병렬 처리

// req_1, req_2 는 프로미스 객체를 리턴하는 함수이다.
async function getData() {
  const p1 = req_1();
  const p2 = req_2();
  const data1 = await p1;
  const data2 = await p2;
  console.log(data1, data2);
}

템플릿 리터럴

  • 템플릿 리터럴은 작은 따움표와 큰따옴표의 혼용이 가능하다.

  • 여러 줄의 문자열을 작성할 수 있다.

  • 문자열 안에서 ${}을 이용해 변수를 사용할 수 있다.

예시

const msg = `확인 결과
'${name}'은 평균 ${score/10}점입니다.`;
// "확인\s결과\n'홍길동'은\s평균\s100점입니다."; // 이런식이 된다.

제너레이터

제너레이터란?

generator는 함수의 실행을 중간에 멈추고 재개할 수 있는 기능

예시

next 메서드

function* f1() {
  yield 10;
  yield 20;
  return 'finished';
}
const gen = f1();
// gen은 next, return, throw 메서드를 가진다.
console.log(gen.next()); // { value: 10, done: false }
console.log(gen.next()); // { value: 20, done: false }
console.log(gen.next()); // { value: 'finished', done: true }

return 메서드

function* f1() {
  yield 10;
  yield 20;
  return 'finished';
}
const gen = f1();
// gen은 next, return, throw 메서드를 가진다.
console.log(gen.next()); // { value: 10, done: false }
console.log(gen.return('done')); // { value: 'done', done: true }
console.log(gen.next()); // { value: undefined, done: true }

throw 메서드

function* f1() {
  trt {
	yield 10;
    yield 20;
  } catch (e) {
    console.log(e);
  }
}
const gen = f1();
// gen은 next, return, throw 메서드를 가진다.
console.log(gen.next()); // { value: 10, done: false }
console.log(gen.throw('error')); // error
console.log(gen.next()); // { value: undefined, done: true }

반복 예시

function* f1() {
  yield 10;
  yield 20;
  yield 30;
}
for (const v of f1()) {
  console.log(v);
}
const arr = [...f1()];
console.log(arr); // [10, 20, 30]

map, filter, take와 같은 함수도 제너레이터를 활용하여 구현할 수 있다.

// 제너레이터를 이용한 map 함수 정의
function* map(iter, mapper) {
  for (const v of iter) {
    yield mapper(v);
  }
}

제너레이터 간 호출

function* f1() {
  yield 2;
  yield 3;
}

function* f2() {
  yield 1;
  yield* f1();
  yield 4;
}
console.log(...f2()); // 1, 2, 3, 4

제너레이터로 데이터 전달

function* f1() {
	const data1 = yield;
    console.log(data1); // 10
  	const data2 = yield;
    console.log(data2); // 20
}

const gen = f1();
gen.next(); // 실행
gen.next(10);
gen.next(20);

0개의 댓글