Front-end/Js

Js 기초(JSON, AJAX)- AWS 풀스택 과정 22일차

awspspgh 2024. 8. 13. 18:23

오늘은 JSON, AJAX에 대해서 배워보겠습니다

 

목차
1. parameter
2. non-standard
3. JSON
4. AJAX
5. 예제 문제
6. 느낀점

 

1. parameter

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>
        parameter (파라미터)
    </h1>
    <ul>
        <li>
            파라미터 개수 관계없이 사용 가능 함수(메서드) 이름이 호출될 때 전달 사용
        </li>
        <li>
            파라미터의 개수가 2개 / 실제 값이 1개처럼 
            파라미터의 개수가 불일치하여 받지 못하는 값이 있다면
            undefined 처리
        </li>
        <li>
            값을 받아오지 못하는 파라미터가 undefined 처리가 되는 걸 막기 위해
            기본값을 설정할 수 있음 => optional parameter
        </li>
        <li>
            모든 파라미터는 arguments라는 프로퍼티를 이용하여 파라미터를 관리
            배열로 담겨서 관리
        </li>
        <li>
            optional parameter는 arguments에 저장되지 않음
        </li>
        <li>
            optional parameter는 다른 파라미터보다 뒤에 있어야 한다. (가장 끝에 존재가능)
        </li>
        <li>
            rest parameter : 남는(이외의, 여분의) 파라미터
        </li>
        <li>
            사용할 파라미터는 일반 파라미터로 배정하고 나머지 파라미터들을 통합하여 하나의
            이름으로 배정하는 기법
        </li>
        <li>
            ... : spread 연산자라고 하여, 배열, 객체를 복제하는데도 사용함.
        </li>
    </ul>
    <script>
        function testFun(p1, p2, p3, p4 = 0, p5 = 0){
            console.log(p1, p2, p3, p4, p5);
            console.log(arguments);
            return p1 + p2 + p3 + p4 + p5;
        }
        console.log(testFun(1,2,3));
        console.log(testFun(1,2,3));
        console.log(testFun(1,2)); // NaN

        function restFun(a,b, ...others){
            console.log(a,b);
            console.log(others);
            others.forEach(function(e){
                console.log(e);
            });
        }
        restFun(1,2,3,4,5,6,7,8,9);
        console.log("-------");
        let oldArr = ['a','b','c','d'];
        let newArr = [...oldArr]; //... 배열복사 기능도 있음
        console.log(oldArr);
        console.log(newArr);
        let newObj = {...oldArr};
        console.log(newObj);

        let num = [1,2,3,4,5,6,7,8,9];
        function sum(a,b, ...others){
            let s = a+b;
            others.forEach((e)=>{
                s += e;
            })
            return s
        }
        console.log(sum(...num));
    </script>
</body>
</html>

 

▷ 출력

 

2. non-standard

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>
        비표준 속성(non-standard attribute)
    </h1>
    <ul>
        <li>
            html 태그의 종류에 따라 속성들이 제한적
            개발자들이 직접 속성을 만들어서 사용할 수 있는 방법을 제공
        </li>
        <li>
            너무 과도하면 개발 효율성과 가독성 저하, 적당히 사용하는 것을 권장
        </li>
        <li class="list" data-name="가나다">
            data-변수명="${값}"
            data-변수명 : 속성명 
            ${값}이 value로 인지할 수 있도록 설계되어 있음
        </li>
        <li class="list" data-Age="20" data-item="listItem">
            읽어 올 때 : dataset.변수명 값이 리턴됨
            dataset property를 사용하여 읽어들임
        </li>
        <li>
            변수명에 대문자는 허용 안 함
            dataset.Age(인지 못함) dataset.age(인식 가능)
            대문자를 사용하더라도 소문자로 변환하여 읽기 가능
        </li>
    </ul>
    <script>
        // querySelector('css선택자') : 처음 만나는 값을 인지
        // querySelector('css선택자') : 모든 값을 인지
        // All은 값이 하나더라도 배열로 인지
        let li_list_tag = document.querySelectorAll('.list');
        console.log(li_list_tag);
        console.log(li_list_tag[0].dataset.name);
        console.log(li_list_tag[1].dataset.Age); // 대문자 인식 못함. undefined
        console.log(li_list_tag[1].dataset.item);

    </script>
</body>
</html>

 

▷ 출력

 

3. JSON

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>
    JSON(JavaScript Object Notation) : 자바 스크립트의 객체 표기법
    </h1>
    <ul>
        <li>
            데이터 요청 및 응답처리에 필요한 데이터의 표준 형식을 제공하는 타입
        </li>
        <li>
            백엔드(서버)언어 종류에 상관없이 데이터를 송수신 단말형식으로 통일
        </li>
        <li>
            백엔드(서버)에서는 무조건 String 처리 - 화면(javaScript)는 Object로 처리
        </li>
        <li>
            화면에서 서버로 데이터를 보낼 때 >
            Object > String => JSON.stringify(jsObject)
        </li>
        <li>
            서버에서 화면으로 데이터를 받을 때 >
            String > Object => JSON.parse(StringData)
        </li>
    </ul>

    <script>
        // '{name: value, name2:value2}' => object > string 변환
        // {name: value, name2:value2} => string > object 변환

        const cake ={
            id:'1234',
            type: 'donut',
            name: 'cake',
            image:{
                url: 'img/001.jpg',
                width: '200',
                height: '20'
            },
            thumbnail:{
                url: 'img/th/001.jpg',
                width: '20',
                height: '5'
            }
        }
        console.log(cake);
        // cake를 string으로 변환
        let cakeString = JSON.stringify(cake);
        console.log(cakeString);
        console.log(typeof cakeString);
        // {"id":"1234","type":"donut","name":"cake","image":{"url":"img/001.jpg","width":"200","height":"20"},"thumbnail":{"url":"img/th/001.jpg","width":"20","height":"5"}}
        
        // 서버에서 온 string => object로 변경
        let stringData ='{"id":"1234","type":"donut","name":"cake","image":{"url":"img/001.jpg","width":"200","height":"20"},"thumbnail":{"url":"img/th/001.jpg","width":"20","height":"5"}}';
        let parseData = JSON.parse(stringData);
        console.log(parseData);

        // 콘솔에 key:value 형식으로 출력
        // for in 사용하여 추출
        // object[keyName] = value 추출
        for(let keyName in parseData){
            if(keyName == 'image' || keyName == 'thumbnail'){
                for(let key in parseData[keyName]){
                    console.log(key + ":" + parseData[keyName][key]);
                }
            }else{
                console.log(keyName + ":" + parseData[keyName]);
            }
        }
    </script>
</body>
</html>

 

▷ 출력

 

4. AJAX

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>
        비동기 통신(asynchronous communication) :  AJAX
        AJAX (asynchronous Javascript And Xml) : javaScript와 xml을 이용한 비동기 정보교환기법
    </h1>
    <ul>
        <li>
            데이터 통신 방식 : 동기, 비동기
        </li>
        <li>
            동기방식(synchronous)
            동시에 일어나는 방식
            동기 방식으로 요청을 하면 페이지로 리턴
            <form>동기방식</form>
            순차적임
        </li>
        <li>
            비동기방식(asynchronous)
            동시에 일어나지 않는 방식
            비동기 방식으로 요청을 하면 string(json)으로 리턴(data만 리턴)
            순차적이지 않음 그자리에서 결과가 바로 주어지지 않을 수도 있음
        </li>
        <li>
            동기와 비동기의 장단점
        </li>
        <li>
            동기 방식 : 직관적, 설계가 간단하다
            결과가 주어지기 전까지는 아무것도 못하고 페이지가 오기를 대기해야 한다는 단점이 있음.
        </li>
        <li>
            비동기 방식: 설계가 복잡하다
            결과가 주어지는데 시간이 걸리더라도, 다른 작업을 할 수 있어 효율적임.
        </li>
        <li>
            비동기 방식 : AJAX 방식 사용
        </li>
    </ul>
    <ul>
        <li>
            async 키워드 : 함수 선언 앞에 붙이는 키워드 (async function(){})
        </li>
        <li>
            await 키워드 : 순차적으로 코드가 실행되어야 할 때 사용
            순차코드 실행을 보증
            지연로딩,  지연 상황이 발생되면 코드 실행이 순차적으로 진행될 수 있도록 보증한다
            이전 라인의 코드 실행이 완료될 때까지 다음 라인은 기다릴 수 있도록 하는 기능
        </li>
        <li>
            async await : 비동기 통신 키워드
        </li>
        <li>
            Promise 객체를 생성 / 이용하여 데이터 통신을 편리하게 할 수 있도록 한다.
        </li>
        <li>
            http://jsonplaceholder.typicode.com/todos
        </li>
    </ul>
    <h3>async await 연습</h3>
    <button type="button" id="btn">데이터 불러오기</button>
    <ul id="ul"></ul>
    <script>

        document.getElementById('btn').addEventListener('click', ()=>{
            asyncFun().then(result=>{
                console.log(result);
                // 여기서 처리
                printData(result);
            });
        });

        function printData(result){
            document.getElementById('ul');
            let str = '';
            for(let key in result){
                str += `<li>${key} : ${result[key]}</li>`;
            }
            ul.innerHTML = str;
        }

        async function asyncFun(){
            try{
                const resp = await fetch('http://jsonplaceholder.typicode.com/todos/1');
                const result = await resp.json(); //body에 내가 요청한 데이터를 싣어줌 => json() 형태로 리턴
                console.log(resp);
                console.log(result);
                return result;
            } catch (error){
                console.log(error);
            } finally{
                console.log("await finish");
            }
        }
    </script>
</body>
</html>

 

▷ 출력

 

◈ promise chain

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>
        promise chain 방식
    </h1>
    <ul>
        <li>
            promise 객체를 리턴하여 값을 가져오면 then 메서드를 실행하여 실행 순서를 기다리게 할 수 있다
        </li>
        <li>
            fetch(url, [config]) : 데이터 통신을 위해 제공되는 함수 url, 통신에 필요한 정도
            config(header에 적용되는 각종 정보를 설정) : 내가 데이터를 보낼 때 사용
        </li>
        <li>
            then : promise 객체를 리턴하는 함수
            메서드를 기다려서 리턴값이 만들어지면 다음 로직으로 연결하는 기능
        </li>
    </ul>
    <button type="button" id="btn">데이터 가져오기</button>
    <ul id="ul">

    </ul>
    <script>
        document.getElementById('btn').addEventListener('click', ()=>{
            fetch('http://jsonplaceholder.typicode.com/todos/2')
            .then(resp => resp.json())
            .then(result => {
                console.log(result);
                printData(result);
            }) // 성공시
            .catch(err => console.log(err)); // 실패시
        })
        function printData(result){
            document.getElementById('ul');
            let str = '';
            for(let key in result){
                str += `<li>${key} : ${result[key]}</li>`;
            }
            ul.innerHTML = str;
        }
    </script>
</body>
</html>

 

▷ 출력

 

▣ 데이터 가져오기

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id="btn">데이터 가져오기</button>
    <ul id="ul"></ul>
    <script>
        //http://jsonplaceholder.typicode.com/todos/1 ~ 5번까지 5개의 데이터를 li로 출력
        
        let num = 0;
        let str = '';
        document.getElementById('btn').addEventListener('click', ()=>{
            for(let i = 1; i <= 5; i++){
                num ++;
                asyncFun(num).then(result=>{
                    console.log(num);
                    // 여기서 처리
                    printData(result);
                });
            }
        });
        
        function printData(result){
            document.getElementById('ul');
            for(let key in result){
                str += `<li>${key} : ${result[key]}</li>`;
            }
            ul.innerHTML = str;
        }
        
        async function asyncFun(N){
            try{
                const resp = await fetch(`http://jsonplaceholder.typicode.com/todos/${N}`);
                const result = await resp.json();
                console.log(resp);
                return result;
            } catch (error){
                console.log(error);
            } finally{
                console.log("await finish");
            }
        }
    </script>
</body>
</html>

 

▷ 출력

 

5. 예제 문제

◎ 문제

▶ 1번

사칙연산 계산기

 

◎ 정답

▶ 1번

- HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="09_style.css">
</head>
<body>
    <div class="calculator">
        <form action="" name="froms">
            <input type="text" id="output">
            <button type="button" class="clear" value="C">C</button>
            <button type="button" class="operator" value="/">/</button>
            <button type="button" value="1">1</button>
            <button type="button" value="2">2</button>
            <button type="button" value="3">3</button>
            <button type="button" class="operator" value="*">*</button>
            <button type="button" value="4">4</button>
            <button type="button" value="5">5</button>
            <button type="button" value="6">6</button>
            <button type="button" class="operator" value="+">+</button>
            <button type="button" value="7">7</button>
            <button type="button" value="8">8</button>
            <button type="button" value="9">9</button>
            <button type="button" class="operator" value="-">-</button>
            <button type="button" class="dot" value=".">.</button>
            <button type="button" value="0">0</button>
            <button type="button" class="operator result" value="=">=</button>
        </form>
    </div>
    <script>
        const output = document.getElementById('output');
        let outputValue = '';

        function operation(f, o, l){
            let result = 0;
            switch(o){
                case "+": result = f + l; break;
                case "-": result = f - l; break;
                case "*": result = f * l; break;
                case "/": result = f / l; break;
            }
            return result.toFixed(2);
        }

        function extractValue(strValue){
            // string 13.5 + 12.3 = 연산자와 피연산자로 나누기
            console.log(strValue);
            let firstNum = strValue.substring(0, strValue.indexOf(" "));
            let operator = strValue.substr(strValue.indexOf(" ")+1, 1); // 시작번지부터 1개
            let lastNum = strValue.substring(strValue.lastIndexOf(" ")+1); // 마지막 공백부터 끝까지
            console.log(firstNum, operator, lastNum);
            // 계산값 호출
            return operation(parseFloat(firstNum), operator, parseFloat(lastNum));
        }

        document.querySelector('.calculator').addEventListener('click', (e)=>{
            // console.log(e.target);  // 내가 선택한 객체
            // console.log(e.target.value); // 내가 선택한 객체의 value 값
            // console.log(typeof e.target.value);
            // eval 함수 : 절대 사용하면 안 됨.
            // NaN => op로 사용
            let btnVal = e.target.value;
            output.value += btnVal;
            if(!isNaN(btnVal)){        // 버튼의 값이 숫자라면...
                outputValue += btnVal;
            }else{
                // 숫자가 아닐 때
                // + - * / . = C undefined(addEventListener 여백 클릭 시)
                if(btnVal != undefined){
                    switch(btnVal){
                        case ".": 
                            // 숫자에 붙어서 소수점 역할을 하기.
                            outputValue += btnVal;
                            break;
                        case "C": 
                            // output 창을 지우기
                            outputValue = '';
                            output.value = '';
                            break;
                        default: 
                            // 사칙연산 + - * / =
                            let sub = ''; // 결과를 받을 변수
                            if(btnVal == '='){
                                // 연산의 결과를 호출(function 작업)
                                sub = extractValue(outputValue); // 결과값 리턴
                                outputValue = sub;
                            }else{
                                outputValue += ` ${btnVal} `; 
                                // string 13.5 + 12.3 =
                                // 이후 function 작업으로 피연산자와 연산자로 분리시킴
                            }
                            break;
                    }
                }
            }
            output.value = outputValue;
        });
    </script>
</body>
</html>

 

- CSS

body{
    background-color: beige;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
}
.calculator{
    border: 1px solid black;
    background: linear-gradient(#C6FFDD, #FBD786, #f7797d);
    padding: 5px;
}
.calculator form{
    display: grid;
    /* 65px 65px 4개*/
    grid-template-columns: repeat(4,65px);
    grid-auto-rows: 65px;
    gap: 5px;
}
.calculator form button, input{
    font-size: 15px;
    border: 2px solid black;
    cursor: pointer;
    padding: 5px;
}
.calculator form button:hover{
    box-shadow: 1px 1px 2px black;
}
.calculator form input{
    grid-column: span 4;
    font-weight: 700;
    background-color: white;
    text-align: right;
}
.calculator form .clear{
    background: linear-gradient(#f12711, #f5af19);
    grid-column: span 3;
    font-size: 20px;
}
.calculator form .operator{
    background: linear-gradient(#e1eec3, #f05053);
}
.calculator form .result{
    background: linear-gradient(#ee0979, #ff6a00);
    grid-column: span 2;
}
.calculator form .dot{
    background: linear-gradient(#FF5F6D, #FFC371);
}

 

6. 느낀 점

배열 안에 객체가 있거나 객체 안에 배열이 경우 또는 배열과 객체가 반복적으로 들어가 있을 때 향상된 for의 for of, for in 어떤 것을 사용해야 할 지 헷갈리기도 하였다. 그래서 중간중간에 막히는 경우도 많았다. 향상된 for에 대해서 복습을 집중적으로 해야겠다.