[3] JavaScript

2024. 8. 14. 17:11Vue

- react custom hook

> 커스텀 hook으로 로직 재사용

 

- DOM/BOM

> document, window(생략가능)

 

- CRUD

C - createElement보다는 innerHTML을 선호한다 - DOM 구조를 몇 번이나 변경하는지

R - querySelector, querySelectorAll, closest ( 아랫쪽, 윗쪽 어디서 찾아가느냐 )

U - classList 

 

Event 모델

- addEventListener()

- 버블링/ 캡처링

- stopPropagation/preventDefault

- EventLoop, 리스너(핸들러), 람다식

엣날 방식 = btn.addEventListener('click', function() {...}, false); 버블링( 안쪽에서 바깥쪽으로 ) 

> 이렇게 하면 function을 재사용하지 못한다.

>> 왜 이렇게 ?

 

모듈패턴 - 보통은 싱글턴 구현하기 위해서 사용했던 방식

> 클로저가 가장 많이 쓰이는 방식

>> 클로저 : 외부에 노출되지 않는 보호되는 데이터 ( 상태라고 한다 ) 

>>>클로저를 이용하면 어떤데이터를 개별적으로 보호할 수 있다.

>>>>이 데이터를 접근하는 함수를 하나 만든다. > 이 함수만 노출을 시킨다.> 외부에서는 노출된 함수만 사용하기 때문에 이 데이터에 직접적으로 접근하지 못하는게 클로저의 장점이다.

- 노출한다는 것 = 리턴한다 > 이것을 하는것이 클로저

> 이거랑 + 를 해서 하나를 더 한다. 즉시 실행함수

>>이 두개를 결합해주면 싱글턴의 효과가 난다.

 

1.sample2.js

2. index.html = src = sample2.js

모듈패턴 = 내가 원하는함수를 반환하기 위해서 사용

 

- 배열로 반환할때도 있다

> react useState , 배열로 반환할때도 있지만 객체를 반환할때도 있다.

 

- Vue3= 리액트를 많이 참고했다.

 

[모듈 패턴]

- 코드단위를 명확하게 분리하고 구성

- 클래스를 모방해서 관련이 있는 함수를 모아 즉시실행함수로 감싸서 하나의 모듈을 만들어 클로저 기반으로 동작한다.

- 한번 실행하면서 클로저(인스턴스변수) 인스턴스변수를 사용하는 메서드를 사용해준다. ( 자바에서 객체만들어준다 생각하면된다)

 

- 즉시실행함수 = 한번 만 실행가능하다

 

 

[순서도]

1. npm create vite@latest

2. 해당 폴더로 이동

3. npm install

4. index.html <script>삭제

5. 상품 product.js -> 상품 목록 반환 작업

6. 카트 -> cart.js -> 장바구니 처리

목표 > 로직 분리

7. 상품 리스트(product.js)

const list = [
    {pno: 1, pname: 'Americano', price: 1500},
    {pno: 2, pname: 'Latte', price: 2500},
    {pno: 3, pname: 'Ice', price: 2000}
    ]

8. getList 노출

export const getList = () => list

 

9. index.html

 

<script type="module">
    import {getList} from './product.js'

    const menuList = getList()
    const menuUL = document.querySelector('.menuDiv ul')
    //menu하나하나를 li태그로 바꿔줄 거다.
    menuUL.innerHTML =
        menuList.map(menu => `<li>
                <div>
                ${menu.pno}
                ${menu.pname}
                ${menu.price}
                </div>
                </li>`).join('')


</script>

10. product.js

export const findMenu = (pno) => list.find(menu=> menu.pno === pno)

11. index.html

<script type="module">
    import {getList, findMenu} from './product.js'

    const menuList = getList()
    const menuUL = document.querySelector('.menuDiv ul')
    //menu하나하나를 li태그로 바꿔줄 거다.
    menuUL.innerHTML =
        menuList.map(menu => `<li>
                <div data-pno="${menu.pno}">
                ${menu.pno}
                ${menu.pname}
                ${menu.price}
                </div>
                </li>`).join('')
    menuUL.addEventListener('click', e => {
        const target = e.target
        console.log(target)
        const pno = target.dataset.pno//문자열로 가져온다.
        const menu = findMenu( parseInt(pno) )

        if (!menu) {
            return
        }
        console.log(menu)
    }, false)//false = 캡처링 안한다.
</script>

 

12. cart.js

상품 => {pno, pname, price}

카트 => [ {pno, pname, price, qty} ]

let cartArr = []

export function addCart(product){
    //전개 연산자
    cartArr.push({...product, qty:1})
}
export const getCart =()=>cartArr

 

13. index - 함수를 파라미터로 던진다.

<script type="module">
    import {getList, findMenu} from './product.js'
    import {addCart, getCart} from "./cart.js";

    const menuList = getList()
    //될수있으면 고정된 값에 걸어라, 동적인것에 걸지말고
    const menuUL = document.querySelector('.menuDiv ul')
    const cartUL = document.querySelector('.cartDiv ul')

    //menu하나하나를 li태그로 바꿔줄 거다.
    menuUL.innerHTML =
        menuList.map(menu => `<li>
                <div data-pno="${menu.pno}">
                ${menu.pno}
                ${menu.pname}
                ${menu.price}
                </div>
                </li>`).join('')
    menuUL.addEventListener('click', e => {
        const target = e.target
        console.log(target)
        const pno = target.dataset.pno//문자열로 가져온다.
        const menu = findMenu(parseInt(pno))

        if (!menu) {
            return
        }

        //console.log(menu)
        addCart(menu, refreshCart)

    }, false)//false = 캡처링 안한다.

    const refreshCart = () => {
        const cartList = getCart()
        cartUL.innerHTML = cartList.map(
            cart => `<li>
            <div data-pno=${cart.pno}>
                ${cart.pno}
                ${cart.pname}
                ${cart.price}
                ${cart.qty}
            </div>
            </li>`).join('')
    }


</script>

14. cart.js - 던져받은 함수를 실행

let cartArr = []

export function addCart(product){
    //전개 연산자
    cartArr.push({...product, qty:1})
    if(callback)
    {
        callback()
    }
}
export const getCart =()=>cartArr

15. cart.js 수정

let cartArr = []

export function addCart(product, callback){
    //전개 연산자
    cartArr.push({...product, qty:1})

    if(callback)
    {
       callback(cartArr)
    }
}

16. index 

<script type="module">
    import {getList, findMenu} from './product.js'
    import {addCart} from "./cart.js";

    const menuList = getList()
    //될수있으면 고정된 값에 걸어라, 동적인것에 걸지말고
    const menuUL = document.querySelector('.menuDiv ul')
    const cartUL = document.querySelector('.cartDiv ul')

    //menu하나하나를 li태그로 바꿔줄 거다.
    menuUL.innerHTML =
        menuList.map(
            menu => `<li>
                <div data-pno=${menu.pno}>
                ${menu.pno}
                ${menu.pname}
                ${menu.price}
                </div>
                </li>`).join('')
    menuUL.addEventListener('click', e => {
        const target = e.target
        console.log(target)
        const pno = target.dataset.pno//문자열로 가져온다.
        const menu = findMenu(parseInt(pno))

        if (!menu) {
            return
        }

        //console.log(menu)
        addCart(menu, refreshCart)

    }, false)//false = 캡처링 안한다.

    const refreshCart = (buyItems) => {
        cartUL.innerHTML = buyItems.map(
            cart => `<li>
            <div data-pno=${cart.pno}>
                ${cart.pno}
                ${cart.pname}
                ${cart.price}
                ${cart.qty}
            </div>
            </li>`).join('')
    }
    </script>

17. cart.js

let cartArr = []

export function addCart(product, callback) {

    //이미카트안에 있었을지도 모르니까
    const findproduct = cartArr.find(cart => cart.pno === product.pno)
    if (findproduct) {
        findproduct.qty += 1
    } else {
        //전개 연산자
        cartArr.push({...product, qty: 1})
    }
    if (callback) {
        callback(cartArr)
    }
}

 

18. 버튼 추가 index

<script type="module">
    import {getList, findMenu} from './product.js'
    import {addCart} from "./cart.js";

    const menuList = getList()
    //될수있으면 고정된 값에 걸어라, 동적인것에 걸지말고
    const menuUL = document.querySelector('.menuDiv ul')
    const cartUL = document.querySelector('.cartDiv ul')

    //menu하나하나를 li태그로 바꿔줄 거다.
    menuUL.innerHTML =
        menuList.map(
            menu => `<li>
                <div data-pno=${menu.pno}>
                ${menu.pno}
                ${menu.pname}
                ${menu.price}
                </div>

                </li>`).join('')
    menuUL.addEventListener('click', e => {
        const target = e.target
        console.log(target)
        const pno = target.dataset.pno//문자열로 가져온다.
        const menu = findMenu(parseInt(pno))

        if (!menu) {
            return
        }

        //console.log(menu)
        addCart(menu, refreshCart)

    }, false)//false = 캡처링 안한다.

    const refreshCart = (buyItems) => {
        cartUL.innerHTML = buyItems.map(
            cart => `<li>
            <div data-pno=${cart.pno}>
                ${cart.pno}
                ${cart.pname}
                ${cart.price}
                ${cart.qty}
            </div>
               <div><!--추가, 몇번인지/ HTML에는 정보만 넣는다.-->
                <button data-pno="${cart.pno}" data-job="plus">+</button>
                <button data-pno="${cart.pno}" data-job="minus">-</button>
                </div>
            </li>`).join('')
    }

    cartUL.addEventListener("click", e=> {
        const target = e.target
        console.log(target)

        const pno = target.dataset.pno
        const job = target.dataset.job

        //데이터 처리 = cart.js

    }, false)
</script>

 

19. cart

let cartArr = []

export function addCart(product, callback) {

    //이미카트안에 있었을지도 모르니까
    const findproduct = cartArr.find(cart => cart.pno === product.pno)
    if (findproduct) {
        findproduct.qty += 1
    } else {
        //전개 연산자
        cartArr.push({...product, qty: 1})
    }
    if (callback) {
        callback(cartArr)
    }
}

export function changeQty(pno, job, callback) {
    const findproduct = cartArr.find(cart => cart.pno === pno)


    if (job === 'plus')
    {
        findproduct.qty += 1
    }
    else if (job === 'minus'){
        findproduct.qty -= 1
    cartArr = cartArr.filter(cart => cart.qty > 0)
    }
    if (callback) {
        callback(cartArr)
    }
    }

 

20. index

<script type="module">
    import {getList, findMenu} from './product.js'
    import {addCart, changeQty} from "./cart.js";

    const menuList = getList()
    //될수있으면 고정된 값에 걸어라, 동적인것에 걸지말고
    const menuUL = document.querySelector('.menuDiv ul')
    const cartUL = document.querySelector('.cartDiv ul')

    //menu하나하나를 li태그로 바꿔줄 거다.
    menuUL.innerHTML =
        menuList.map(
            menu => `<li>
                <div data-pno=${menu.pno}>
                ${menu.pno}
                ${menu.pname}
                ${menu.price}
                </div>

                </li>`).join('')
    menuUL.addEventListener('click', e => {
        const target = e.target
        console.log(target)
        const pno = target.dataset.pno//문자열로 가져온다.
        const menu = findMenu(parseInt(pno))

        if (!menu) {
            return
        }

        //console.log(menu)
        addCart(menu, refreshCart)

    }, false)//false = 캡처링 안한다.

    const refreshCart = (buyItems) => {
        cartUL.innerHTML = buyItems.map(
            cart => `<li>
            <div data-pno=${cart.pno}>
                ${cart.pno}
                ${cart.pname}
                ${cart.price}
                ${cart.qty}
                ${cart.price * cart.qty}
            </div>
               <div><!--추가, 몇번인지/ HTML에는 정보만 넣는다.-->
                <button data-pno="${cart.pno}" data-job="plus">+</button>
                <button data-pno="${cart.pno}" data-job="minus">-</button>
                </div>
            </li>`).join('')
    }

    cartUL.addEventListener("click", e=> {
        const target = e.target
        console.log(target)

        const pno = target.dataset.pno
        const job = target.dataset.job

        //데이터 처리 = cart.js
        changeQty(parseInt(pno), job, refreshCart)

    }, false)
</script>

 

[화면 처리와 순수 로직의 분리]

- 화면쪽 작업

- 데이터를 렌더링 - 상황에 맞게

- 이벤트 처리

- JS의 복잡성이 증가 - 자바스크립트는 모아서 모듈로 빼버리면 된다. 문제점 : HTML과 JS는 같이있어야 한다. 

> 이걸 뺄 수 있으면 좋겠다 > 결과적으로 필요한것

>> 화면(HTML) + 이벤트처리 + 상태 데이터 : 이렇게 하나의 단위로 구성을 해야 한다. -> Vue, React =컴포넌트 

 

 

[지도 API]

카카오 디벨로퍼 

앱키 : 985d15d1ee0e4a532eb93aebfb132c41

플랫폼 : web

문서화 작업

JSON으로 처리

[7!4d9

{  가게번호: 1 , 가게이름: '가게이름', lat: 32.xxxxxx, lng:127.xxxxxx  }

{  sno: 1, sname: '가게이름',  lat: 32.xxxxxx, lng: 127.xxxxxx}

{   sno: 1, sname: 'funnybeer', lat: 35.150596, lng: 129.115766 }

]


- 화살표 함수를 많이 쓰는 이유 = this

- 동적인 것들은 addEventListener가 안걸린다.

> createElement를 해서 addEvenetListener를 걸 수 있다. 

 

 

 

[axios]

- node.js와 browser를 위한 비동기 처리 클라이언트

- axios : 외부에서 데이터를 가져오는 것

- npm install axios

- 고정된 데이터, 주어진데이터 : 화면에 출력해줘야했다

- 사용자가 생성하는 데이터 : 화면에 출력 이벤트 처리 + 외부데이터

- 자바스크립트가 어려워지는 이유 : 화면출력, 이벤트처리, 외부데이터

- axios : 외부데이터를 쉽게 가져다 쓰는 라이브러리( 외부데이터 로딩하는 라이브러리 )

> URL상에 있는 데이터를 가지고 온다.(크롤링해서 데이터 쓰면안되나? > 안된다.)

>> 외부데이터 쓸때는 보안문제가 생긴다.

>>> localhost:5173을 쓸때는 맘껏 써도된다 > 문자열로 데이터를 가져왔다.

- eval > 문자열을 자바스크립트로 처리되어버린다. ( 보안상으로 위험하다 ) 

- axios API를 쓰는것이 서버통신에 가장 짧은 코드를 짤 수 있다.

- 기본이 JSON이다.

 

 

[ Ajax ]

1. 의도

2. 처리

- Ms가 만들었다. 왜?  > 운영체제, 브라우저 > 브라우저에서 운영체제와 통신하는것을 만들고 싶었다. > ActiveX

> 로컬머신 

- 브라우저가 외부리소스와 통신하기를 원했다 ( 다른 URL과 통신 ) 

> 처음에 나왔을때는 Ajax라는 언어이다. ( Asynchronous nc Javascript & xml )

- 이벤트와 비슷한 방식을 고려한다.

 

 

 

 

 

- W3C Ajax

> 과거에는 자바스크립트가 이정도로올라갈것이라고 생각하지 못했다. 순수한 데이터를 xml에 저장했었다.

- on이라는 단어가 나오면 외부 데이터를 받는것

 

- 비동기모델, 이벤트를 쓸 수 밖에 없었는지?

> 선행작업이 끝날 때까지 다음작업을 할 수 없기때문에 이벤트로 등록해놓으면 결과가 왔을때 이벤트 핸들러만 처리해주면 되기때문에. 이런방식의 코딩을 적용한것이 비동기프로그래밍이다.

>> 비동기 프로그래밍 : 이벤트와 같다고 보면된다.

>>>자바스크릡트는 클릭이벤트만 처리하던앤데 이제는 서버통신도 한다.

 

ex) IOT : device, 휴대폰, 브라우저

- 수많은 디바이스가 있는데 종류가 틀리다.

- 만약 엄청난 데이터를 가지고있고 이 데이터를 어디선가 쓰고싶다면? > 안드로이드, 애플, pc등등에서 사용하기위해선 그것에 맞게 해줘야하는데 그럼 비용이 엄청나게 든다.

- 그래서 이 데이터를 줄게 > 니가 알아서 써

> 이게 가장 돈을 쉽게 벌 수 있는 방법

- ASP, JSP > 과거의 서버는 데이터를 만들어서 보내줬다.(서버에서 화면에 만들필요가 없어졌다 요즘은)

- 하지만 요즘 시대는 데이터만 가지고 브라우저에서 처리 가능

- 그래서 서버에서는 JSon이나, XML데이터만 만들어준다.

- 이것의 몫 (마지막) 은 브라우저의 몫이다.

 

- 자바스크립트 promise

'Vue' 카테고리의 다른 글

[6] JS - Vue  (0) 2024.08.21
[5] JS - Vue3 (2)  (0) 2024.08.20
[4] JavaScript  (0) 2024.08.19
[2] JavaScript  (0) 2024.08.13
[1] JavaScript  (0) 2024.08.12