실전 리엑트 프로그래밍 2장

2장. ES6+를 품은 자바스크립트, 매력적인 언어가 되다.

변수를 정의하는 새로운 방법: const, let

새로운 방법이 나온 이유는 기존 방식으로는 해결되지 않는 문제가 있었기 때문.

var 가 가진 문제

  1. 함수 스코프

    정의된 변수가 함수 스코프(변수가 사용될 수 있는 영역) 를 가진다는 것. 즉 정의된 함수의 스코프를 벗어난 곳에서 호출되면 error.

    function method() {
    i = 1;
    }
    function method2() {
    console.log(i);
    }
    console.log(i); // error
    method();
    method2(); // 1

    반복문을 벗어난 후에도 호출 되는 문제

    for(var i=0; i<10; i++) {
    console.log(i);
    }
    console.log(i); // 10

    → for, while, swich, if문 등 함수 내부에서 작성되는 모든 코드는 같은 문제를 가짐.

  2. 호이스팅

    var 로 정의된 변수는 그 변수가 속한 스코프의 최상단으로 끌어올려짐.

    console.log(variable); // undefined
    var variable = 1;
    // 변수의 정의가 위로 끌어올려 졌지고 값은 해당 위치에서 할당 되어 버림.
  3. 변수의 재정의가 가능.

    → 직관적이지 않고 버그로 이어질 수 있음.

블록스코프를 가진 const, let

const, let도 호이스팅이 되지만, 변수가 정의되기 전에 사용하려고 하면 참조 에러가 발생한다.

console.log(foo); // reference...error....
///// 임시적 사각지대 (temporal dead zone)
const foo = 1;
///////////// const가 호이스팅을 한다는 건 아래와 같음.
const foo2 = 1;
{
console.log(foo2); // reference error
const foo2 = 2;
}
// 만약 foo2를 호이스팅 하지 않았다면 console.log는 에러가 발생하지 않았을테지만
// 동일 스코프에 새로이 정의된 foo2를 바라보고 있기 때문에 임시 대드존으로 참조 에러 발생!

Arrow function

  1. arguments

    arrow 함수는 this나 arguments가 바인딩 되지 않는 함수이므로, 사용하고 싶다면

    const foo = (...rest) => console.log(rest);
    foo(1,2,3); // [1,2,3]
  2. this

  • 일반 함수에서 this 는 호출 시점에 사용된 객체로 binding,
  • 생성자 함수 내부에서 정의된 arrow 함수의 this는 생성된 객체를 참조
function foo() {
this.value = 1;
this.increase = () => this.value++;
}
const obj = new foo();
obj.increase();
console.log(obj.value); // 2
const increase = obj.increase();
increase(); // this 는 생성된 객체를 참조
console.log(obj.value); // 3
////////
const bar = {
value: 1,
increasae: function() {
this.value++;
}
}
bar.increase();
console.log(bar.value); // 2
const increase2 = bar.increase();
increase2(); // window의 increase2();...
console.log(bar.value); // 2
  • setInterval 에 인자로 전달된 함수는 전역 환경에서 실행되기 때문에 함수 스코프 내부의 this를 보지 않고 window를 보게 됨. → var _this = this; 이런짓을 ..하기도 함. —> closure

Closure 함수가 생성되는 시점에 접근 가능했던 변수들을 생성 이후에도 계속해서 접근할 수 있게 해줌. 접근할 수 있는 변수는 그 함수를 감싸고 있는 상위 함수들의 매개 변수, 내부 변수.

function foo() {
this.value = 1;
var that = this;
// arrow 함수를 사용하면 이런 편법을 쓰지 않아도 this는 함수..
setInterval(function increase() {
that.value++;
}, 1000);
}
//////
function makeFunc(x) {
return function add(y) {
return x+y;
}
}
const add5 = makeFunc(5); // --> add는 상위 함수의 매개변수인 x에 접근할 수 있다.
console.log(add5(1)); // 6 --> add5가 생성된 이후에도 상위 함수를 호출할 때 사용했던 인수에 접근할 수 있다.
const add7 = makeFunc(7);
console.log(add7(1)); // 8 --> add는 따로따로 클로저가 생긴다.
console.log(add5(1)); // 6

Promise프로미스

  • 비동기 상태를 값으로 다룰 수 있는 객체.
  • 비동기 프로그래밍을 동기 프로그래밍 방식으로 코드를 작성할 수 있음.
  • 이전에는 콜백 패턴을 많이 사용 → 콜백이 조금만 중첩돼도 코드가 복잡해지는 단점.
  • 상태는 pending: 결과를 기다리는 중, fulfilled: 수행이 정상적으로 끝났고 결괏값을 찾고 있음, rejected: 수행이 비정상으로 끝났음 의 3 가지중 하나로 존재한다. 이중 fulfilled, rejected 상태를 settled 상태라고 부른다.
  • 대기 상태(pending)가 아니면 더 이상 다른 상태로 변경되지 않는다.
  • 생성하는 방법
// 1 new
const p1 = new Promise((resolve, reject) => {
resolve(data);
// or reject('error message');
});
// new를 사용하지 않고 Promise.reject를 호출하면 거부됨 상태의 프라미스 생성
const p2 = Promise.reject('error message');
// 입력값이 프라미스라면 그 객체가 그대로 반환, 아니라면 fulfilled 상태의 프로미스 생성.
const p3 = Promise.resolve(param);
  • 프로미스 예외는 명시적으로 catch로 잡아주는 편이 좋음. → catch 이후에도 then을 쓸 수 있음.
  • 프로미스는 불변객체이다.

Async, Await

async, await 함수는 프로미스를 반환한다.

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

await 함수는 오직 async 함수 내부에서만 사용될 수 있다.

async, await가 프라미스보다 가독성이 좋다.

function foo() {
func1().then(data => console.log(data); return func2();)
.then(data => console.log(data))
}
async function bar() {
const data1 = await func1();
console.log(data1);
const data2 = await func2();
console.log(data2);
}

동기, 비동기 모두 catch 에서 예외가 처리됨.

Generator

map, filter, take 를 만들어 쓸 수 있음.

function* map(iter, mapper) {
for( const v of iter ) {
yield mapper(v);
}
}
function* filter(iter, test) {
for( const v of iter) {
if(test(v))
yield v;
}
}
function* take(n, iter) {
for( const v of iter ) {
if( n <= 0) return;
yield v;
n--;
}
}
const values = [1,2,3,4,5,6,7,8,9,10];
const result = take(3, map(filter(values, n => n % 2 === 0), n => n * 10 ));
console.log([...result]); // [20, 40, 60]

J3
백엔드, 프론트엔드 가리지 않고 모두 관심많은 초절정미녀 개발자입니다~!!