Front-End

[한입 크기로 잘라 먹는 리액트(React.js)] 섹션 2. JavaScript 응용

cloudmato00 2023. 10. 20. 15:06

이정환님의 인프런 [한입 크기로 잘라 먹는 리액트(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
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)

  • 응용 프로그램 프로그래밍 인터페이스