[한입 크기로 잘라 먹는 리액트(React.js)] 섹션 2. JavaScript 응용
이정환님의 인프런 [한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지]강좌를 참고하여 작성하였습니다.
https://www.inflearn.com/course/%ED%95%9C%EC%9E%85-%EB%A6%AC%EC%95%A1%ED%8A%B8#
한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지 - 인프런 | 강의
개념부터 독특한 프로젝트까지 함께 다뤄보며 자바스크립트와 리액트를 이 강의로 한 번에 끝내요. 학습은 짧게, 응용은 길게 17시간 분량의 All-in-one 강의!, 리액트, 한 강의로 끝장낼 수 있어요.
www.inflearn.com
Truthy & Falsy
- 참 같은 값이 truthy, 거짓 같은 값이 falsy이다.
- 다음 표는 공식문서(https://developer.mozilla.org/ko/docs/Glossary/Falsy)를 참고.
truthy | falsy |
falsy값이 아닌 값들. | null undefined false NaN 0 -0 0n "" (비어있는 string 값, '' ``도 포함) documant.all(Object) |
삼항 연산자
🍅삼항 연산자
let a = 3;
//일반 조건문 이용
if(a >= 0) {
console.log("양수");
} else {
console.log("음수");
}
//삼항 연산자 이용
a >= 0 ? console.log("양수") : console.log("음수");
- (조건식) ? (참일 때 수행할 식) : (거짓일 때 수행할 식)
const arr = [];
//일반 조건문 이용
if(arr.length === 0) {
console.log("빈 배열");
} else {
console.log("안 빈 배열");
}
//삼항 연산자 이용
arr.length === 0 ? console.log("빈 배열") : console.log("안 빈 배열");
🍅삼항 연산식의 대입
const arr = [1, 23];
const arrayStatus = arr.length === 0 ? "빈" : "안빈";
console.log(arrayStatus); //안빈
- 대입 연산자를 이용하여 삼항 연산자의 반환값을 대입할 수도 있다.
🍅삼항 연산자의 truthy, falsy 이용
let a = [];
const result = a ? true : false;
console.log(result); //true
🍅삼항 연산자의 중첩
//TODO : 학점 계산 프로그램
//90점 이상 A+
//50점 이상 B+
//둘 다 아니면 F
let score = 40;
score >= 90
? console.log("A+")
:score >= 50
?console.log("B+")
:console.log("F");
//F
- 하지만 보기 힘들다는 단점이 있다.
let score = 40;
if (score >= 90) {
console.log("A+");
} else if(score >= 50) {
console.log("B+");
} else {
console.log("F");
}
- 이런 경우 일반 조건문이 더 가독성이 좋다.
단락 회로 평가
🍅true와 false에서의 단락 회로 평가
console.log(true && true); //true
console.log(true || false); //true
console.log(!true); //false
🍅truthy와 falsy에서의 단락 회로 평가
const getName = (person) => {
if(!person) {
return "객체가 아닙니다."
}
return person.name;
};
let person;
const name=getName(person);
console.log(name); //객체가 아닙니다.
- 해당 함수를 단락 회로 평가를 이용하여 단축해보자.
const getName = (person) => {
return person && person.name;
};
let person;
const name=getName(person);
console.log(name); //undefined
- 논리 연산에서 person은 undefined라는 falsy한 값으로 인식되기 때문에 뒤에 있는 값을 고려하지 않는다.
- 이때 falsy했기 때문에 값을 그대로 리턴하여 undefined라는 값이 반환된다.
- person이 null이 였을 경우 null이 반환된다.
const getName = (person) => {
const name = person && person.name;
return name || "객체가 아닙니다";
};
let person;
let person1 = {name: "cloudmato"};
const name = getName(person);
const name1 = getName(person1);
console.log(name); //객체가 아닙니다.
console.log(name1); //cloudmato
- 반환할 값을 설정해 줄 수도 있다.
조건문 업그레이드
🍅includes 이용
function isKoreanFood(food) {
if(food === "불고기" || food === "비빔밥" || food === "떡볶이") {
return true;
}
return false;
}
const food1 = isKoreanFood("불고기");
const food2 = isKoreanFood("파스타");
console.log(food1); //true
console.log(food2); //false
- 케이스가 너무 많기 때문에 큰 의미가 없다.
function isKoreanFood(food) {
if(["불고기", "떡볶이", "비빔밥"].includes(food)) {
return true;
}
return false;
}
const food1 = isKoreanFood("불고기");
const food2 = isKoreanFood("파스타");
console.log(food1); //true
console.log(food2); //false
- includes 메서드를 이용해여 배열 안에 존재하는지 확인하는 식으로 변경
🍅프로퍼티 접근 이용
const meal = {
한식 : "불고기",
일식 : "초밥",
인도식 : "커리",
중식 : "멘보샤"
};
const getMeal = (mealType) => {
return meal[mealType] || "굶기";
};
console.log(getMeal("중식")); //멘보샤
console.log(getMeal()); //굶기
비 구조화 할당
let arr = ["one", "two", "three"];
let one = arr[0];
let two = arr[1];
let three = arr[2];
console.log(one, two, three);
- 해당 3개의 할당 과정을 한 줄로 바꿔보자.
🍅배열의 기본 변수 비구조화 할당
let arr = ["one", "two", "three"];
let [one, two, three] = arr;
console.log(one, two, three);
- 이렇듯 대괄호를 이용해서 배열의 값을 순서대로 할당받아서 사용할 수 있는 방법을 배열의 비구조화 할당이라고 한다.
🍅배열의 선원분리 비구조화 할당
let [one, two, three] = ["one", "two", "three"];
console.log(one, two, three);
- 더 줄일 수 있다.
🍅swap에서의 비구조화 할당 이용
let a = 10;
let b = 20;
let tmp = 0;
tmp = a;
a = b;
b = tmp;
console.log(a, b); //20,10
- 해당 코드를 줄여보자.
let a = 10;
let b = 20;
[a,b] = [b,a];
console.log(a, b); //20, 10
- 비구조화 할당을 이용하여 swap이 이루어졌다.
🍅객체의 비구조화 할당
let object = {one: "one", two: "two", three: "three"};
let one = object.one;
let two = object.two;
let three = object.three;
console.log(one, two, three); //one two three
- 해당 코드를 줄여보자.
let object = {one: "one", two: "two", three: "three", name: "cloudmato"};
let {name, one, two, three} = object
console.log(one, two, three, name); //one two three cloudmato
- 객체에서도 배열의 비구조화 할당을 사용할 수 있다.
- 이때 순서는 상관 없다. 왜냐하면 순서가 아닌 키값을 기준으로 할당이 이루어지기 때문.
- 키값을 이용하여 비구조화 할당을 해야한다는 변수 이름에 대한 한계가 있다. 하지만 극복할 수 있는 방법이 있다.
let object = {one: "one", two: "two", three: "three", name: "cloudmato"};
let {name: myName, one, two, three} = object
console.log(one, two, three, myName); //one two three cloudmato
- 다음과 같이 원래 키값: 내가 사용하고 싶은 변수이름 이런 식으로 명시해주면 다른 변수명으로 할당 가능하다.
let object = {one: "one", two: "two", three: "three", name: "cloudmato"};
let {name: myName, one, two, three, abc="four"} = object
console.log(one, two, three, myName, abc); //one two three cloudmato fore
- abc = "four"과 같이 기본값을 설정해 줄 수도 있다.
Spread 연산자
🍅객체에서의 spread연산자의 사용
const cookie = {
base: "cookie",
madeIn: "korea"
};
const chocochipCookie = {
...cookie,
toping: "chocochip"
};
const blueberryCookie = {
...cookie,
toping: "blueberry"
};
const strawberryCookie = {
...cookie,
toping: "strawberry"
};
console.log(chocochipCookie);
console.log(strawberryCookie);
console.log(blueberryCookie);
// { base: 'cookie', madeIn: 'korea', toping: 'chocochip' }
// { base: 'cookie', madeIn: 'korea', toping: 'strawberry' }
// { base: 'cookie', madeIn: 'korea', toping: 'blueberry' }
- 스프레드 연산자(...)를 통해서 객체의 중복되는 프로퍼티를 펼쳐 사용할 수 있다.
🍅배열에서의 spread연산자 사용
const noTopingCookies = ['촉촉한쿠키', '안촉촉한쿠키'];
const topingCookies = ['바나나쿠키', '블루베리쿠키', '딸기쿠키', '초코칩쿠키'];
const allCookies = [...noTopingCookies, "함정쿠키", ...topingCookies];
console.log(allCookies);
//[ '촉촉한쿠키', '안촉촉한쿠키', '함정쿠키', '바나나쿠키', '블루베리쿠키', '딸기쿠키', '초코칩쿠키' ]
- 다음과 같이 배열에서도 사용할 수 있다.
- 배열의 내장함수인 concat을 사용할 수도 있지만 스프레드 함수를 사용하면 중간에 '함정쿠키'와 같이 유연하게 활용을 할 수 있다.
동기 & 비동기
:순서대로 실행하는 것과 그렇지 않은 것들
🍅동기 방식의 처리 - 블로킹 방식
- 자바스크립트는 싱글 스레드 언어이다.
- 자바 스크립트는 코드가 작성된 순서대로 작업을 처리한다.
- 이전 작업이 진행 중일 때는 다음 작업을 수행하지 않고 기다린다.
- 먼저 작성된 코드가 다 실행이 된 이후에 뒤에 작성된 코드를 실행한다.
- Tread - taskA----- taskB--------------- tastC--|
🍅동기처리 방식의 문제점
- 하나의 작업이 너무 오래 걸리게 될 시,
- -> 모든 작업이 오래 걸리는 하나의 작업이 종료되기 전까지 대기해야 한다.
- -> 전반적인 흐름이 느려진다.
🍅멀티 쓰레드
- 코드를 실행하는 일꾼 Thread를 여러 개 사용하는 방식인 멀티 쓰레드 방식으로 작동시키면 분할 작업이 가능하다.
- 오래걸리는 일이 있어도 다른 Tread에게 지시하는 방식.
- Tread taskA----|
- TreadA taskB----------|
- TreadC taskC--|
- 그러나 자바스크립트는 싱글쓰레드 사용.
🍅비동기 작업 - 논블로킹 방식
- 싱글 쓰레드 방식을 이용하면서, 동기적 작업의 단점 극복을 위해 여러 개의 작업 동시에 실행시킴
- 즉, 먼저 작성된 코드의 결과를 기다리지 않고 다음 코드를 바로 실행한다.
- Tread taskA----|
- taskB-------------|
- taskC--|
- 비동기 처리를 할 때는 우리가 자바스크립트에서 함수를 호출할 때 콜백 함수를 붙여서 그 비동기 처리의 결과값이나 끝났는지의 여부를 확인하는 역할을 하게 된다.
🍅코드로 확인하기
function taskA() {
console.log("A작업 끝");
};
taskA();
console.log("코드 끝");
/*결과
A작업 끝
코드 끝
*/
- 우리가 알게 모르게 사용해왔던 동기적 방식.
- taskA가 끝난 후에야 다음 코드가 실행된다.
function taskA() {
setTimeout(() => {
console.log("A TASK END");
}, 2000)
};
taskA();
console.log("코드 끝");
/* 결과
코드 끝
A TASK END
*/
- 먼저 지시된 작업을 끝나기까지 기다리지 않고 그냥 다음 작업업을 바로 실행하는 비동기 방식.
- setTimeout함수는 두 개의 파라미터를 받는다. (콜백함수, 시간(ms단위))
function taskA(a, b, cb) {
setTimeout(() => {
const res = a + b;
cb(res);
}, 3000)
};
taskA(3,4,(res)=>{
console.log("A TASK RESULT : ", res)});
console.log("코드 끝");
/**
* 코드 끝
* A TASK RESULT : 7
*/
🍅자바스크립트엔진의 비동기 처리
- 작성한 글 날라감 이슈로 그림만..
Promise - 콜백 지옥에서 탈출하기
- 자바스크립트의 비동기를 돕는 객체
- 비동기 처리의 결과값을 핸들링하는 코드를 비동기 함수로부터 분리할 수 있다.
🍅비동기 작업이 가질 수 있는 3가지 상태
🍅콜백 함수를 이용한 비동기 처리
//2초 후에 이 수가 양수인지, 음수인지 판단하는 함수.
function isPositive(number, resolve, reject) {
setTimeout(() => {
if(typeof number === "number") {
//성공 -> resolve
resolve(number >= 0? "양수":"음수")
} else {
//실패 -> reject
reject("주어진 값이 숫자형 값이 아닙니다")
}
},2000)
};
isPositive([], (res)=> {
console.log("성공적으로 수행됨 : ", res);
}, (err)=> {
console.log("실패 하였음 : ", err);
});
🍅Promise 사용
- 어떤 함수가 promise를 반환한다는 것은 이 함수는 비동기 작업을 하고 작업의 결과를 promise 객체로 반환 받아서 사용할 수 있는 함수라는 것이다.
function isPositiveP(number) {
const executor = (resolve, reject) => {
setTimeout(()=>{
if(typeof number === "number") {
//성공 -> resolve
console.log(number);
resolve(number >= 0? "양수":"음수")
} else {
//실패 -> reject
reject("주어진 값이 숫자형 값이 아닙니다")
}
},2000);
};
const asyncTask = new Promise(executor);
return asyncTask;
}
const res = isPositiveP([]);
res.then((res)=>{console.log("작업 성공 : ", res)}).catch((err)=>console.log("작업 실패 :", err));
🍅Promise로 콜백지옥 탈출하기
function taskA(a,b,cb) {
setTimeout(()=>{
const res = a+b;
cb(res);
}, 3000);
}
function taskB(a,cb) {
setTimeout(()=>{
const res = a * 2;
cb(res);
}, 1000);
}
function taskC(a,cb) {
setTimeout(()=>{
const res = a * -1;
cb(res);
}, 2000);
}
taskA(3,2,(a_res)=>{
console.log("taskA : ", a_res);
taskB(a_res,(b_res)=>{
console.log("taskB : ", b_res);
taskC(b_res,(c_res)=>{
console.log("taskC : ", c_res);
});
});
});
- 이전코드이다.
- 콜백이 계속 안으로 들어가며 콜백헬, 콜백 지옥이 생긴 모습이다.
- Promise로 해결해보자.
function taskA(a,b) {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
const res = a+b;
resolve(res);
}, 3000);
});
}
function taskB(a) {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
const res = a * 2;
resolve(res);
}, 1000);
});
};
function taskC(a) {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
const res = a * -1;
resolve(res);
}, 2000);
});
}
taskA(5,1).then((a_res)=>{
console.log("A RESULT : ", a_res);
taskB(a_res).then((b_res)=>{
console.log("B RESULT : ", b_res);
taskC(b_res).then((c_res)=>{
console.log("C RESULT : ", c_res);
});
});
});
- 기대한 것과는 다르다.
- 그 이유는 then을 콜백 함수를 쓰는 식으로 사용했기 때문.
- 바꿔서 다시 해보자.
function taskA(a,b) {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
const res = a+b;
resolve(res);
}, 3000);
});
}
function taskB(a) {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
const res = a * 2;
resolve(res);
}, 1000);
});
};
function taskC(a) {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
const res = a * -1;
resolve(res);
}, 2000);
});
}
taskA(5,1).then((a_res)=>{
console.log("A RESULT : ", a_res);
return taskB(a_res);
})
.then((b_res)=> {
console.log("B RESULT : ", b_res);
return taskC(b_res);
})
.then((c_res)=>{
console.log("C RESULT : ",c_res);
});
- 이렇게 then으로 계속해서 이어나가는 방식을 then chaining방식이라고 한다.
- 이런 방법이 가능한 이유는 return으로 promise를 반환해준 것이나 마찬가지기 때문에 then을 사용할 수 있는 것이다.
- 콜백을 계속 이용했다면 > 이런 모양으로 들어가게 되는데 promise를 사용함으로써 해결이 되었다.
const bPromiseResult = taskA(5,1).then((a_res)=>{
console.log("A RESULT : ", a_res);
return taskB(a_res);
});
console.log("dfdfdfdf");
console.log("dfdfdfdf");
console.log("dfdfdfdf");
console.log("dfdfdfdf");
bPromiseResult
.then((b_res)=> {
console.log("B RESULT : ", b_res);
return taskC(b_res);
})
.then((c_res)=>{
console.log("C RESULT : ",c_res);
});
- 이런 식으로 중간에 다른 식을 끼워 넣은 후에 호출할 수 있다는 장점도 있다.
- 따라서 promise함수를 사용하면 콜백 함수를 피하고 좀 더 가독성 있고 깔끔한 비동기 처리를 할 수 있도록 도와준다.
async & await - 직관적인 비 동기 처리 코드 작성하기
- async와 await는 promise를 더 쉽고 가독성 좋게 작성할 수 있게 해준다.
🍅async
//async
function hello() {
return 'hello';
}
async function helloAsync() {
return 'hello Async';
}
console.log(hello()); //hello
console.log(helloAsync()); //Promise { 'hello Async' }
- hello()의 결과값과 달리 helloAsync()는 Promise객체가 그대로 리턴되었다.
- async를 함수 앞에 작성하면 자동으로 promise객체를 리턴하는 비동기 처리 함수가 된다.
//async
function hello() {
return 'hello';
}
async function helloAsync() {
return 'hello Async';
}
helloAsync().then((res)=>{
console.log(res);
})
//결과: hello Async
- helloAsync()함수는 Promise를 리턴하기 때문에 then으로 정리해주었다.
🍅await
function delay (ms) {
return new Promise((resolve)=>{
setTimeout(resolve,ms);
})
}
async function helloAsync() {
return delay(3000).then(()=>{
return 'hello Async'})}
helloAsync().then((res)=>{
console.log(res);
})
//결과: hello Async
- await을 사용하지 않은 코드
function delay (ms) {
return new Promise((resolve)=>{
setTimeout(resolve,ms);
})
}
async function helloAsync() {
await delay(3000);
return "hello async";
}
helloAsync().then((res)=>{
console.log(res);
})
//결과: hello Async
- await을 사용한 코드
- await키워드를 비동기 함수의 호출 앞에 붙이게 되면 비동기 함수가 마치 동기적인 함수처럼 작동을 하게 된다.
- await키워드는 async키어드가 붙은 함수 내에서만 사용할 수 있다.
function delay (ms) {
return new Promise((resolve)=>{
setTimeout(resolve,ms);
})
}
async function helloAsync() {
await delay(3000);
return "hello async";
}
async function main() {
const res = await helloAsync();
console.log(res);
}
main();
//결과: hello Async
API 호출하기
🍅API (Application Programming Interface)
- 응용 프로그램 프로그래밍 인터페이스