Day2
오늘 강의 주제
Javascript 훑어보기
x라는 변수에 10이라는 값을 넣을 수 있다.
let x = 10;
javascript에서 모든 함수는 값을 반환하게 되어있다.
return 이 있다면 해당 값을 반환하고, 아닐경우 undifined를 반환한다.
function foo() {} //return undifined;
function bar() {
return 0 ;
} // => 함수 정의 문 (값) -> 문 뒤에 ;을 붙이지 않음
const bar = function bar() {}; // => 함수 정의 식
bar();
함수를 값으로 취급할 땐 이름을 생략 할 수 있다. 이러한 함수를 익명 함수 라고 하며 IIFE(즉시 실행 함수)를 만들어서 사용한다. 재귀호출할 때는 이름을 생략하지 않는다.
const bar = function bar() {}; // => 함수 정의 식
bar(); //const bar을 호출한것
function bar → 값으로 여겼기 때문에 이름 생략가능 하다.
const bar = function() {};
즉시 실행 함수(IIFE)
단 한 번만 실행할 때 사용한다.
javascript에서 ()를 치게 되면 값으로 여기고 이름을 생략할 수 있다.
(function(){})()
콜백함수(함수 위임)
인자로 함수를 받고, 함수의 호출을 위임하는 것이다.
function foo(x) { // 함수를 인자로 받음.
x();
return fuction() {
}; // 값으로서 return 하니 함수 정의 식 (이름 생략 가능)
}
const y = foo(function () {
})
함수 ⇒ 코드를 묶어놓은 값.
화살표 함수
es6이후 부터 등장한 함수 선언 방식
const foo = function foo() {
foo(); // 재귀 호출을 할 때는 function foo()를 호출함.
};
위의 구조를 아래와 같이 쓸 수 있다.
화살표 함수의 this
는 동적 바인딩 되는 일반함수와 달리 상위 스코프의 this를 가리킨다.
const bar = () => {}
(표현)문과 (정의)식
js문법은 크게 식/문 으로 나눌 수 있다. 코드를 실행 했을 때 값으로 마무리 되면 식
; ⇒ 식의 마무리
0;
1 + 10;
foo(); // return undifinded 받으니 식
문에는 if문, 반복문이 있다. 문 뒤에는 ;를 붙이지 않는다.
if() {}
while() {}
new 연산자
new 연산자로 호출하게 되면 빈객체를 만든다.
함수에게 빈객체를 전달하고 빈객체는 this로 접근 가능하다. 내부상 매커니즘은 프로토타입으로 동작한다.
const x = 10; // 불변의 속성
const y = () => 10; // 가변을 할 수 있음 // 한줄 함수
const a = {};
a.name = ''; // 동적 바인딩
console.log(a); // {name:''}
function foo() {
this.ab = 10; // new 연산자를 통해 받은 빈객체를 받음. 빈객체에 동적 바인딩
}
const y = new foo(); //인스턴스 객체. 객체 형태를 위임
y instanceof foo // true.
Class
ES6에 등장한 개념이다. Class는 내부적으로는 함수로 되어있다.
function foo() {
this.name();
}
class bar {
constuctor() {
this.name = 10;
}
}
foo
, bar
객체를 정의하고 같은 결과를 만들어 낸다. 하지만 아래와 같은 차이를 가지고 있다.
- foo(일반 함수) → new 연산자 없이 호출 가능. new를 강제 할 수 없음.
- bar(Class) → new를 강제 할 수 있음.
new
를 강제해야 한다면 Class문법을 사용하는 것이 좋다.
this
함수는 실행되는 순간 소유자를 확인한다.
this
는 소유자에 따라 동적 바인딩된다.
const person = {
name: 'kim',
getName() {
return this.name;
}
}
console.log(person.getName()); //실행되는순간 소유자를 확인 (호출자 = person)
소유자가 벗겨저 의도한 대로 this
가 동작하지 않는 상황이 생길 수 있다.
javascript에서 기본적으로 this
는 window 객체를 가리킨다.
const man = person.getName;
man();
// 소유자가 벗겨짐
// 실행되는 순간 호출자를 확인 => 호출자가 없음. => 호출자가 없으면 전역(window)객체를 호출자로 바라봄
콜백 함수로 넘기게 되면 소유자가 벗겨진다. 대표적인 예로 이벤트 등록 시 넘기는 이벤트 콜백 함수의 this는 전역(window)객체를 가리킨다.
// -----
button.addEventListener('click', person.getName);
// 콜백. 함수를 넘겨주면서 소유자가 벗겨짐. this => 전역객체
bind
, call
, apply
를 사용하면 사용자가 의도한대로 this
를 할당해 줄 수 있다.
button.addEventListener('click', person.getName.bind(person));
// bind 안에 객체를 this로 넘겨줌
person.getName.call(person) // 호출 시 this가 될 객체를 받음
closure
함수 foo가 호출되면 스코프가 벗겨짐에 따라 함수 안의 변수(x)는 사라지지만 함수 bar의 실행 컨텍스트에 저장되어 bar에서 x변수의 값을 알 수 있다.
function foo(x) {
return function bar() {
return x;
}
}
const f = foo(10);
console.log(f());
아래와 같이 리터럴 방식의 객체를 선언하면 객체 안의 변수가 바뀌는 것을 막을 수 없다.
const person = {
age : 10,
}
person.age = 500;
클로저로 객체 안의 내용을 은닉할 수 있다.
function makePerson() {
let age = 10;
return {
getAge() {
return age;
},
setAge(x) {
return age;
}
}
let p = makePerson();
// 호출하는 순간 makePerson의 스코프가 벗겨지고, 안에 함수에 age값이 캡쳐됨.
console.log(p.getAge());
비동기
javascript는 싱글스레드이기 때문에 특정 동작을 실행하는 동안 블록이 생겨 지연된다.
Promise
Promise는 자바스크립트 비동기 처리에 사용되는 객체이다.
Promise 이전에 보통 콜백함수를 통해 비동기 처리를 했었다. 아래와 같이 코드의 depth가 깊어지고, 예외처리가 곤란해지는 경우가 발생할 수 있다.
setTimeout(function (x) {
console.log('foo');
setTimeout(function(y) {
console.log('bar');
}, 2000);
}, 1000); //콜백으로 넘겨줌. 1초 후에 실행 후 또 다른 함수를 호출해야 함
// 이렇게 콜백이 길어지면 콜백지옥...
Promise를 사용하면 이런 콜백패턴이 가진 담점을 보완하고 비동기 처리 시점을 명확하게 할 수 있다.
Primise객체는 인자로 resolve
, reject
함수를 받는다.
- resolve → 성공. then에 입력된 함수를 호출
- reject → 실패. catch에 입력된 함수 호출
const p1 = new Promise((resolve, reject) => {
setTimeout(() => { //api라 가정
resolve('응답'); // resolve응답 출력
}, 1000);
resolve();
reject();
//
}); // promise라는 내장객체를 인스턴스화 함..
const p2 = new Promise((resolve, reject) => {
setTimeout(() => { //api라 가정
resolve('응답2'); // resolve응답 출력
}, 1000);
});
//then함수를 내장하고 있음.
p1.then(p2)
.then(function(r) {
console.log('resolve' + r) ;
})
.catch(function(){
})
async, await (백그라운드 = Promise)
aysnc는 비동기 함수. 동기식 코드를 짜듯이 비동기식 코드를 짤 수 있다.
aysnc함수 내에서 await를 사용할 수 있다. awaitd 사용 시 resolve가 실행돼서 마무리가 될 때까지 다음 줄로 넘어가지 않는다.
const delay = ms => new Promise(resolve => setTimeout(resolve, ms); // 지연시키는 방법
//delay를 실행하면 promise객체 반환
async function main() {
console.log('1');
try {
const x = await delay(2000); // 2초 동안 지연 시킴
}catch(e) {
//reject가 발생하면 catch에 잡힘
}
console.log('2');
}
main();
함수 관련 참고하면 좋을 강사님의 글
Redux
Redux를 직접 만들어보자(예제 링크)
규칙
- 앱하나에 store 하나 만듦. (여러개 만들 수 있지만 통상적으로)
- store는 밑으로 흘러가는 데이터관리.
- 컴포넌트가 store의 상태를 수정할 수 없음. immutable한 상태여야 함.
- 컴포넌트가 store상태를 바꾸려면 redux에 reducer 콜백으로 넘겨줌
- reducer 안에서 상태 업데이트.
- reducer가 호출될 때 현재 상태를 넘겨줌.
- redux에서 상태를 바꾸는것을 reducer 함수로 함.
createStore
를 살펴보자.
state는 return으로 반환한 함수 이외에 접근이 불가능 하다. (클로저로 데이터 보호)
ui 컴포넌트에서 action을 던지는 행위를 dispatch
로 한다.
dispatch
로 subscribe
를 통해 등록된 함수를 차례로 실행한다.
//redux.js
export function createStore(reducer) {
let state; //클로저로 데이터를 보호
const listeners = [];
const getState = () => ({...state});
// js는 참조 복사, 그대로 내보내고 외부에서 변경하면 그대로 내부 객체가 변경됨
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(fn => fn());
};//ui 컴포넌트에서 action을 던지는 행위를 dispatch로 함
const subscribe = (fn) => {
listeners.push(fn)
}
// store 가 변경 됨을 알려야 함
return {
getState,
dispatch,
subscribe,
};
}
UI컴포넌트 코드를 살펴보자.
createStore를 통해 store객체를 받고, store의 상태가 업데이트 됐을 때 실행되어야 하는 함수를 subscribe
함수를 통해 넘겨준다(구독).
reducer
를 통해 상태를 업데이트 시킨다.
reducer
에서는 객체 불변성을보장을 위해 항상 새로운 객체를 return 해줘야한다. (redux에서 약속🤙)
//index.js. 컴포넌트 역할
import { createStore } from "./redux.js";
const INCREMENT = 'increment'; // action type;
const RESET = "reset";
function reducer(state = {}, action) {
if(action.type === INCREMENT) {
return {
...state,
count: state.count? state.count + 1: 1
} // 항상 새로운 객체를 return을 해줘야 함. redux약속
} else if (action.type === RESET) {
return {
...state,
count: action.resutCount,
}
}
return state;
}
const store = createStore(reducer);
function update() {
//이 함수가 호출되면 redux에 store 변경이 일어난것,
console.log(store.getState());
}
store.subscribe(update);
function actionCreater(type, data) {
return {
...data,
type,
}
} // action type 생성
function increment() {
store.dispatch(actionCreater(INCREMENT));
}
function reset() {
store.dispatch(actionCreater(RESET, {resutCount: 10}))
}
increment();
reset();
해당 포스팅은 우아한 테크러닝3기 React&TypeScript 강의를 정리한 내용입니다.