2021-11-16(화) 2주차 2일

Jeongyun Heo·2021년 11월 16일
0

브라우저가 하나의 플랫폼이 되길 원한다

옛날에는 화면 보여주면 끝나는 애였음

오늘은 개인 메모장 만들어 볼 거

로컬 스토리지 이용해서 처리

로컬 스토리지 안에 배열을 넣고 빼는 거

배열 연습에서 다른 점은 딱 2가지
1. 데이터를 꺼내는 부분
2. 데이터를 저장할 수 있는 부분
객체 리터럴

HTML5에 Geolocation 기능이 있음
Geolocation : 위치를 추적하는 기능

KNN 내일이나 모레쯤 하려고 함

오늘은 배열을 끝까지 다뤄볼 거임

어제 한 게 MVC보다 다음 단계였음

과연 수업시간에 리액트까지 나갈 수 있을까
보여준다고 해도 이해할 수 있을까

로컬 스토리지

window.localStorage
https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage

localStorage 읽기 전용 속성을 사용하면 Document 출처의 Storage 객체에 접근할 수 있습니다. 저장한 데이터는 브라우저 세션 간에 공유됩니다.

브라우저 안에 저장되는 정보라고 생각하면 됨

localStorage.setItem('myCat', 'Tom');

키, 값 저장하는 거
객체 리터럴이랑 같음

위에서 추가한 localStorage 항목을 읽는 법은 다음과 같습니다.

const cat = localStorage.getItem('myCat');

그리고 제거는 아래와 같습니다.

localStorage.removeItem('myCat');

setItem, getItem, removeItem 이 3가지만 기억하면 됨

이걸 사용하면 데이터를 넣어놨다가 끄집어 와서 사용할 수 있게 됨

storageEx.html 파일 만들기

로컬 스토리지라는 애가 실제로 있는지 확인해보자

window.localStorage인데 window 생략 가능함

localStorage.setItem(키, 값)

localStorage.setItem("sample", "Hello World")

개발자 도구 확인해보기

한 페이지 내에서 저장하고 끄집어 내서 사용하는 건 당연히 가능

A 페이지에서 저장한 걸 B 페이지에서 끄집어 내는 것도 가능

extract.html 파일 생성

가지고 올 때도 sample 이라는 이름으로 가져오면 됨

localStorage.getItem(키)

<script>
    const msg = localStorage.getItem("sample")

    document.write(`<h1>${msg}</h1>`)
</script>

document.write() ← 가능하면 안 쓰는 게 좋음
body 안에 내용물을 다 지워버림
브라우저에 있는 내용을 지우고 새로 써버림
innerHTML 대신에 그냥 한 번 써봤음

어제 계속 다뤘던 게 영화 데이터
영화 데이터는 객체 리터럴이였음
데이터와 로직을 구분하는 패턴 중요함

우리가 만드는 데이터는 거의 객체 리터럴임
객체 리터럴을 저장하면 어떻게 되나
로컬 스토리지에 저장할 수 있는 데이터는 문자열 밖에 없음

객체는 이렇게 못 들어감
객체 리터럴도 저장하면 실제로 이렇게 못 들어감

객체 리터럴을 하나 만든다

// storageEx.html
<script>
    const obj = {name: "Hong Gil Dong", age: 16, address: "한양"}
    
    localStorage.setItem("sample", obj)
</script>

object Object로 저장이 되어 버린다
우리가 원하는 대로 저장이 되지 않는다
왜냐하면 여기에는 문자열 밖에 못 들어가니까

JSON : 데이터 교환하는 포맷

JSON으로 바꿔보자

JSON은 속성-값 쌍 또는 키-값 쌍으로 이루어진 데이터 오브젝트를 전달하기 위해 인간이 읽을 수 있는 텍스트를 사용하는 개방형 표준 포맷이다.

https://www.json.org/json-ko.html

JSON(JavaScript Object Notation)은 경량의 DATA-교환 형식이다.

더글라스 크락포드

마크업 랭귀지가 데이터를 표현하는 거가 속도도 느리고 좀 불편하기도 하고
브라우저들이 초반에 점유율 가지고 싸웠
최대한 많은 사용자를 확보해야 됨
태그라는 건 쌍이 맞아야 됨
예를 들어 h1 태그를 쓰면 <h1>...</h1> 이런 식으로 써줘야 됨
그런데 규칙을 안 지키는 경우가 많았음
브라우저는 사용자들을 확보해야 되니까 규칙이 안 맞아도 그냥 보여줌
엄격하게 태그를 만들자
HTML → XHTML(Extensible Hypertext Markup Language)
<book></book> 이거는 책이야
뿌리를 보면 XML이 더 위이고 HTML이 더 아래에 있음
더글라스 크락포드가 XML 너무 불편해. 자바스크립트의 객체 리터럴 쓰면 편할 거 같다고 주장한 게 JSON
JSON으로 데이터를 주고 받음
거의 표준이 돼버림

우리가 수업시간에 배운 건 객체 리터럴 이란 거고
JSON은 문자열임
이 둘 사이의 관계가 어떻게 되느냐
객체 리터럴에 좀 더 문자스러운 표기방법인 것 뿐
객체 리터럴을 문자열로 바꿀 때 쿼테이션 같은 게 붙으면 JSON이 되는 거

다른 점은 따옴표가 있다는 거

엄격하게 태그를 만들자

XHTML(Extensible Hypertext Markup Language)
XHTML은 HTML과 동등한 표현 능력을 지닌 XML 마크업 언어로, HTML보다 엄격한 문법을 가진다.

우리가 수업시간에 배우는 건 객체 리터럴
json은 그냥 문자열
이 두 개를 어떻게 해석을 해야 되나
객체 리터럴에 좀 더 문자스러운 표기방법일 뿐
쿼테이션 붙은 것일 뿐

자바스크립트 객체를 문자열로 바꾸는 방법 : JSON.stringify()
문자열을 자바스크립트 객체로 바꾸는 방법 : JSON.parse()

메소드 2개만 기억하면 됨
이거를 이용해서 웹도 처리하고 앱도 처리하는 거

다른 탭 클릭하면
처리중입니다 라고 뜨고
Network탭 보면 하나가 옴
문자열이 온 거

어플리케이션 형태처럼

탭을 클릭하면 데이터를 가져옴

영화 데이터 추가하면 화면을 갱신해줬음

어제 영화 데이터를 뿌렸던 것처럼 얘도 화면에 뿌려주는 거

처리중입니다 (스피너)
서버에서 데이터를 가지고 오니까 시간이 좀 걸리니까 로딩 메시지를 보여주는 거

호출했을 때 실제로 가지고 오는 데이터는 문자열일 뿐

우리가 영화 데이터를 새로 추가하면 showList() div
영화 목록 화면에 추가해서 보여준 거

어제 우리의 경우는

stringify : 문자화 시킨다

로컬 스토리지에는 문자열 저장만 가능하다

<script>
    const obj = {name: "Hong Gil Dong", age: 16, address: "한양"}

    // 자바스크립트 객체 -> JSON(문자열)으로 변환
    const jsonStr = JSON.stringify(obj)
    
    console.log(jsonStr)
 
    localStorage.setItem("sample", jsonStr)
</script>

JSON 포맷

자바에서도 이 작업을 많이 함

JSON이 각각의 언어마다 라이브러리를 지원해줌

extract.html

console.dir() : 매개변수로 전달된 객체의 속성을 출력한다.

<script>
    const msg = localStorage.getItem("sample")
    
    // JSON(문자열)을 자바스크립트 객체로
    const obj = JSON.parse(msg)

    console.dir(obj)
</script>

배열도 담을 수 있음
배열도 JSON으로 넣을 수 있고 끄집어 낼 수도 있음

다음주 화요일 과제 키오스크

음식점 메뉴 데이터
메뉴 데이터를 저장을 해놨다가 나중에 필요할 때마다 끄집어내서 사용
배열도 한 번 다뤄볼 예정


앱 iOS
앱 Android
다른 서비스
다른 서비스

요즘에는 서버 가지고 웹페이지 만들지 않음
그런 거 하는 서버는 따로 두고
최근에는
서버쪽이 웹페이지를 만드는 건 옛날
서버쪽은 데이터만 제공하는 트렌드
나머지는 전부 다 프론트엔드에서 데이터를 가져와서 처리하는 트렌드
최근 트렌드는 서버에서는 데이터만 줌
이 트렌드를 할 때 제일 많이 쓴 게 JSON

배열도 한 번 다뤄봐야 함

2교시 시작

공통의 포맷이 있어야 됨
문자열
문자열을 이용해서 구조화된 데이터를 표현

객체 티러럴이랑 다른 점은 딱 하나

title : "이터널스"  ---->  "title" : "이터널스"

key에도 큰따옴표가 붙음

이번 시간에는 배열 데이터를 처리해보자

storageEx.html

배열 하나 선언하기

    const arr = [
        {name: '샤프', price: 3000},
        {name: '볼펜', price: 1500},
    ]
    
    localStorage.setItem("products", JSON.stringify(arr))

배열인데 문자열로 바뀐 형태로 저장된 걸 볼 수 있을 거

JSON 포맷으로 변환돼서 저장됨

JSON 포맷에서는 배열을 꺾쇠[]로 표현한다

어? 이거 JSON 문자열이네
자기네가 쓰는 라이브러리 이용해서 처리 가공해서 사용
라이브러리 이용해서 자기한테 맞게 가공해서

브라우저 내에 저장한 거
이 브라우저를 사용하는 동안은 언제든 로컬 스토리지에 있는 거 꺼내서 사용할 수 있음

로컬 스토리지가 원래는 로그인 처리 때문에 나옴

블로그 광고
내가 아이폰을 검색했다는 걸 어떻게 안 것인가
쿠키 라는 것을 이용
구글이 제3자 쿠키 막으려고 함
동의 없이 검색했던 정보를 가져가는 거

구글이 사용자 프라이버시 강화를 이유로 구글 크롬 제 3자 쿠키 중단을 선언했습니다.

사용자 동의 없이 정보를 가져감
제 3자 쿠키 막아줌
그거에 대한 대안으로 나온 게 로컬 스토리지
원래는 로그인 한 정보를 보관하고

지금도 쿠키 많이 씀
모든 쿠키를 브라우저에서 차단할 수 있음

저장은 여기서 하고 꺼내는 건 다른 데서 하고
로컬 스토리지를 쓰면 여러 페이지를 만들어도 마음대로 꺼내서 쓸 수 있음

자바나 자바스크립트에서 배열 같은 건 프로그램이 실행되는 동안만 유지

얘네들은 브라우저를 죽였다가 다시 살려도 그대로 유지되어 있음
영속성 persistence (없어지지 않고 오래 동안) 지속됨
보통은 프로그래밍 짤 때 영속성에 대한 대상을 데이터베이스를 씀

이번엔 끄집어 내보자

localStorage.getItem("products") 여기서 나오는 건 문자열

const products = JSON.parse(arrStr) 자바스크립트 객체로 바꿈

객체로 바꿨으니까 루프 돌릴 수 있음

// extract.html
<script>
    const msg = localStorage.getItem("sample")

    // JSON(문자열)을 자바스크립트 객체로
    const obj = JSON.parse(msg)

    console.dir(obj)

    const arrStr = localStorage.getItem("products")

    const products = JSON.parse(arrStr)

    for (let i = 0; i < products.length; i++) {
        console.log(products[i])
    }

</script>

화면은 화면대로 제작을 하고
자바스크립트는 자바스크립트대로 제작을 해볼 거

개인적인 다이어리라고 생각

localStorage 안에 내가 그동안 써왔던 메모들이 있다고 생각. 배열일 거임.
어플리케이션이 실행이 되면 로컬 스토리지에 있는 메모장에 있는 데이터를 가져다가 로딩해서 배열로 자바스크립트 객체로 바꿔서 관리를 시작
새로운 메모 등록하기도 하고
저장 버튼 누르면 배열을 JSON(문자열)로 바꿔서 로컬 스토리지에 저장을 해준다

댓글 내용도 다 JSON으로 가져옴

Application
localStorage에 있는 데이터를 로딩해서 배열
실행 → 로딩 → 배열 → 관리
새로운 메모 등록
배열 → JSON(문자열) → localStorage에 저장
스피너가 뜨는 곳은 거의 다 JSON을 사용한다고 보면 됨

클로저

클로저
돼지저금통
var는 쓰지 마라. let이랑 const만 써라.
진짜 이유가 여기서 나옴

todo1.html

day6/todo1.html

todo1.html 파일 생성

자바스크립트 함수 f(x) => y
x가 정해지면 y 값이 정해져 있다
항상 같은 값이 나온다
상태가 없다는 뜻
프로그램을 짜다 보면 상태를 유지할 수 있는 방법이 필요
가장 대표적인 게 돼지저금통

자바스크립트의 함수는 1급 객체
변수의 위치에 함수 가능

변수가 3개 있는데 배열에 담을 수 있을까? 당연히 가능
const obj1 = 10
const obj2 = 20
const obj3 = 30

클로저는
자바스크립트를 고급스럽게 쓰고 싶으면 반드시 필요한 기술
면접에서 항상 물어보는 문제이기도 함

<script>
    // 함수 f(x) => y
    // 상태가 없다
    
    const obj1 = 10
    const obj2 = 20
    const obj3 = 30
    
    const arr = []
    
    arr.push(obj1)
    arr.push(obj2)
    arr.push(obj3)
    arr.push(40)   // 이렇게 넣을 수도 있음
    
</script>

함수는 변수 위치에 모두 들어갈 수 있다고 했음

이것도 가능하다는 얘기

<script>
    // 함수 f(x) => y
    // 상태가 없다

    const obj1 = 10
    const obj2 = 20
    const obj3 = 30

    const arr = []

    arr.push(obj1)
    arr.push(obj2)
    arr.push(obj3)
    arr.push(40)
    arr.push(function() {console.log('AAA')}) // 함수

    console.dir(arr)

</script>

arr[4] 함수를 끄집어 낸다

실행하고 싶으면 ()

arr[4]에 함수가 들어있으니까 arr[4]() 이렇게 하면 함수를 실행시킬 수도 있음

자바스크립트는 변수가 들어갈 수 있는 위치에 함수가 들어갈 수 있다

루프 돌려서 push 할 수도 있음

<script>
    const arr = []

    for (let i = 0; i < 10; i++) {
        arr.push(i)
    }

    console.log(arr)

</script>

배열 안에 0부터 9까지 숫자가 들어갔다.

배열 안에 함수를 집어 넣을 수 있다고 했음

그러면 for루프 돌면서 함수를 만들어서 넣는 것도 가능하지 않겠나

<script>
    const arr = []

    for (let i = 0; i < 10; i++) {
        arr.push(function() {console.log('AA')})
    }

    console.log(arr)

</script>

배열을 확인해보니 f가 쭉 나옴
배열 안에 함수들만 들어가 있다는 얘기

루프를 돌리면 함수를 하나씩 꺼낼 수 있음. 그리고 그 함수를 실행할 수 있음.
arr[i]에 함수 들어있으니까 arr[i]()로 함수 실행 가능

<script>
    const arr = []

    for (let i = 0; i < 10; i++) {
        arr.push(function() {console.log('AA')})
    }

    console.log(arr)

    console.log("----------------------------")

    for (let i = 0; i < arr.length; i++) {
        arr[i]()  // 함수 실행
    }

</script>

AA라는 글자가 10번 찍힌다.

여기서 2군데 바꿀 거임

for루프의 반복 변수 ilet에서 → var로 바꿔줌
console.log('AA')console.log(i)로 바꿔줌

<script>
    const arr = []

    for (var i = 0; i < 10; i++) {    // let => var
        arr.push(function() {console.log(i)})  // 'AA' → i
    }

    console.log(arr)

    console.log("----------------------------")

    for (let i = 0; i < arr.length; i++) {
        arr[i]()  // 함수 실행
    }

</script>

var 라고 했더니 10이 10번 찍힌다.

이번에는 varlet으로 변경

<script>
    // 함수 f(x) => y
    // 상태가 없다

    const arr = []

    for (let i = 0; i < 10; i++) {     // var => let
        arr.push(function() {console.log(i)})
    }

    console.log(arr)

    console.log("----------------------------")

    for (let i = 0; i < arr.length; i++) {
        arr[i]()  // 함수 실행
    }

</script>

0, 1, 2, 3, 4, 5, 6, 7, 8, 9 출력

이것도 클로저임

arr 이라는 애가 있고 이 안에 10개가 들어있다
이 10개가 함수를 가리키고 있다
함수 10개가 각각 따로 따로 있는 거

arr[0]()
arr[1]()

함수의 내용물 ↓

function () {
    console.log(i); 
}

이 함수를 보면 i 라는 변수는 선언되지 않았다.
이 함수 안에는 i 라는 변수가 존재하지 않았다.
i 라는 변수는 이 함수에는 없다.
이 함수의 바깥쪽에 존재한다.

<script>
    const arr = []

    for (var i = 0; i < 10; i++) {   // 여기에 존재함
        arr.push(function() {
            console.log(i)
        })
    }

    console.log(arr)

    console.log("----------------------------")

    for (let i = 0; i < arr.length; i++) {
        arr[i]()
    }

</script>

var 라고 쓰면 호이스팅이 일어나서 window에 붙음
이 함수들은 i가 없음
not defined가 뜨는 게 맞는 거
자바스크립트의 클로저는 감춰져 있는 참조라고 말한 적이 있음
뭔가 특별한 장치를 하지 않았는데 자동으로 연결고리를 맺어준 거
나는 아무것도 안했는데 연결이 된 거
i 라는 값을 써야만 하는데 나는 아무것도 안 했는데 연결이 된 거
이게 클로저. 눈에 보이지 않는 참조.
이 함수에는 그 변수가 없었음.
그런데 함수의 바깥쪽에 그 변수가 있어서 그 변수를 사용하고 있는 거. 걔를 그냥 참조하고 있는 거.
왜 i가 10이 나왔을까
var 라고 했더니 10이 나왔고 let 이라고 했더니 0, 1, 2, 3, ..., 9가 나옴
클로저 라는 건 어떤 메모리 공간을 나도 모르게 참조하고 있는 거
감춰진 참조 라고 생각하기

var
자바스크립트의 변수의 scope는 기본이 함수★★★
함수라는 걸 단위로 변수의 scope를 잡는다

전역변수
윈도우창
브라우저
이 공간이 변수의 scope가 된다

함수 안에 선언하는 변수 = 지역변수

var 라고 하면 호이스팅 됨. 전역에 달라붙음. 전역변수임.
i 라는 변수를 참조하는 게 아니라 i가 속한 공간을 참조하고 있는 거.
지금 같은 경우는 window

변수를 var로 선언한 경우 ↓

<script>
    for (var i = 0; i < 10; i++) {   // var로 선언
        console.log(i)
    }

    console.log("after " + i)  // 가능함
</script>

var 라고 하면 브레이스의 영향을 받지 않는다.

i는 10이라고 나온다.

var 라는 애가 잡는 공간의 메모리 범위가 다르기 때문

변수를 let으로 선언한 경우 ↓

<script>
    for (let i = 0; i < 10; i++) {   // let으로 선언
        console.log(i)
    }

    console.log("after " + i)  // 에러
</script>

i is not defined 라고 에러가 난다

일반적인 scope

Lexical Scope 렉시컬 스코프

코딩에서의 scope는 brace 중괄호를 기준으로 잡힘

let 이라는 변수는 루프를 벗어날 수 없는 거

i 값을 참조하는 게 아니라 i를 가지고 있는 메모리 공간을 참조하는 거
그 메모리 공간에서 i 값은 지금 10이다.
윈도우창이라고 생각

let으로 하면 결과가 다름
let 이라고 했더니 0, 1, 2, 3, ..., 9가 나옴

let이나 const를 쓰는 진짜 이유가 이거임

let으로 선언하면 루프에 있는 공간이
루프를 실행하는 공간이 i의 공간이 됨
아까는 window에 있는 i를 바라보고 있는데
이번에는 루프를 실행할 때 루프를 실행하는 공간이 있음
그 공간 자체를 따로따로 무는 거
let
i가 실행되는 공간을 다 따로따로 물고 있음

클로저
원래 이 함수 안에는 i라는 변수는 존재하지 않았음
그런데 i라는 변수를 써야되는 상황
그럼 어디에 있는 i를 써야 되는지 판단을 해야 됨
let 이라는 애를 쓰면 루프를 돌 때마다 생기는 let
루프를 실행하는 공간을 바라봄
var 라고 하면 전역공간을 바라보게 되는 거
혼동이 안 되려면 let 같은 걸 써야만 안전하게 코딩 가능

대신에 장점도 있음

함수가 실행되면서 사용하는 메모리 공간이 있는데
함수는 실행하면 자기만의 메모리 공간을 만들어냄
그런데 자기한테 없는 메모리 공간이 필요. i가 선언되어 있는 메모리 공간이 필요.
개발자가 아무것도 안 해도 이 공간을 사용하는 거를 클로저라고 한다.
클로저 : 암묵적인 참조
내가 직접 가져다 쓰는 게 아니라, 내가 나한테 없는 변수를 바깥쪽에 선언된 변수를 가져다 그냥 썼는데 그 메모리 공간을 참조하고 있는 거
클로저 closure

그럼 이거 어디에다 써먹으라는 거야
얘를 어떻게 써먹느냐

함수는 실행되고 나면 상태를 유지하지 못 함
그런데 상태를 유지해야 될 때가 있음
외부에서 함수를 실행하는데 그 함수가 내부적으로 다른 변수를 참조해서 쓰고 있으면
마치 그 변수를 이용해서 뭔가 작업을 계속 할 수 있는 것처럼 되는 거

맨 위에 있는 함수를 실행하면 배열에 뭔가 추가하고
두 번째 함수를 실행하면 배열에서 뭔가 빼고
세 번째 함수를 실행하면 뭔가 수정하고

내가 사용하는 건 함수 자체
이 배열은 실제로 접근이 안 됨

아까 var 라고 했을 때 전부 다 10이 나왔었음
그렇다는 건 배열 안에 있는 10개의 모든 함수가 전부 다 똑같은 애를 참조하고 있었던 거

예를 들어 함수 안에 어떤 변수가 선언되어 있고 걔가 클로저로 사용이 되는 중이다
함수 안에 선언된 배열 같은 거는 외부에서 접근이 안 됨
그래서 클로저네..

외부에서는 볼 때는 함수만 보임
배열은 안 보임
배열은 접근이 안 됨
외부에 아예 노출이 안 됨
함수 안에 선언된 지역변수거든

function 안에 변수를 선언할 수 있음
그 변수는 외부에서 가져다 쓸 수 없음
그 변수는 지역변수예요

근데 클로저를 이용하면 이 함수를 통해서 여기 있는 애를 건드릴 수는 있음
하지만 외부에서 다이렉트로 연결되는 건 못 하게 막음
마치 금고가 있고 금고지기가 있는 거 같은 거임
객체 지향에서 이런 걸 정보의 은닉이라고 말한다

함수 안에 지역변수가 있고
이 지역변수를 물고 있는 함수들이 있다고 가정
문지기들을 통해서 보물의 내용을 바꿀 수 있다

장점
원래 함수는 상태 유지가 안 됐음
근데 지역변수를 공유해서 씀
상태를 유지하는 게 됨
로직과 상태를 결합한 걸 객체라고 함

자바스크립트에서는 넓은 의미에서 메모리 공간을 차지하면 객체로 본다고 했었음

하지만 자바에서 말하는 인스턴스는 클래스에서 찍어 나온 애를 말하는 거
자동차
속성과 동작

프로그램에서 다루는 2가지
데이터 → 변수/구조체/자료구조
로직 → 함수

돼지를 만들었는데 돈도 보관하고 싶고 기능도 추가하고 싶은 거
그게 자바의 객체
자바에서 말하는 인스턴스라는 건 얘가 데이터도 가지고 있고 이 안에 로직도 있는 거
그거를 자바에서 객체라고 부름
우리는 데이터는 객체 리터럴 같은 거로 따로 배우고 로직은 함수라는 걸로 따로 배움
그런데 우리도 상태를 유지할 필요가 있음
입금을 하면 금액이 계속 쌓여야 됨. 그게 상태. 함수로는 불가능했음.
원래 순수한 함수는 f(x) = y
어제는 꼼수 부림. 데이터를 바깥쪽에 선언함.
어제 영화 데이터를 바깥쪽에 빼놓음.
하지만 바깥쪽에 빼놓으면 누군가 마음대로 바꿀 수 있음. 위험한 거.
그렇게 바깥쪽으로 다 빼놓은 걸 전역변수라고 부름.
변수의 값을 마음대로 바꿀 수 있는 거 위험
전역변수 global variable 공공재 라는 얘기

공공재가 아닌 나를 통해서만 접근하도록
내가 상태를 유지하면서 뭐도 하고 싶은데
외부에서는 데이터를 못 하게 하고 싶고 안전하게 데이터를 유지하고 상태를 유지하고 싶음
그게 바로 자바스크립트에서는 클로저를 써서 처리한다는 거
자바스크립트에서 클로저를 쓰는 것도 많은 지식이 필요함
그래서!! 자바스크립트가 똑같이 클래스 라는 개념을 만들어냄

클래스
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes

옛날에는 그냥 객체 리터럴로 선언함
객체 리터럴은 주로 구조화된 데이터를 표현하기 위해 씀

순수한 함수와 객체에 묶여있는 함수를 구분해서 메서드라고 부름
사실 다른 게 아닌데

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
  // Getter
  get area() {
    return this.calcArea();
  }
  // 메서드
  calcArea() {
    return this.height * this.width;
  }
}

const square = new Rectangle(10, 10);

console.log(square.area); // 100

객체에 묶여 있는 함수를 메서드라고 한다

클래스 brace를 이용해서 데이터와 로직을 같이 넣어 놓음

const square = new Rectangle(10, 10);
new로 찍어내는 거

자바랑 똑같음

new : 새로운 메모리 공간
새로운 메모리 공간에다 만들어 넣는 거
그 메모리 공간을 가리키는 키워드가 this

내가 새로운 메모리 공간을 잡아놓고 걔를 실행하면 그 메모리 공간에 height 라는 애를 만들어 놓는 거고 width라는 애를 만들어 놓는 거

클래스. 객체. 인스턴스.

원래 자바스크립트는 이런 기능이 없었음

시간이 지나다보니까 자바스크립트도 상태를 유지할 수 있는 방법이 필요

원래는 자바스크립트 순수한 함수는 f(x) => y이기 때문에
상태라는 걸 유지할 수 있는 방법이 없었는데
클로저를 이용해서 외부에 있는 다른 함수에 있는 데이터를 가져다 쓸 수 있는 방법이 생기면서 상태를 유지할 수 있는 방법이 생겼다.

클로저라는 개념은 자바스크립트에만 있는 개념은 아님
모든 함수형 언어는 클로저라는 개념을 가지고 있다

자바스크립트에서 클로저를 이용하면 상태를 유지할 수 있구나

이제 클로저를 이용해서 이쁘게 만들어보자

3교시 시작

todo2.html

day6/todo2.html

자바스크립트에서 가장 많이 이용하는 패턴
클로저를 이용한 모듈 패턴

todo CRUD

todo2.html 파일 생성

변수 위치에 함수 가능
함수 안에 변수를 선언하는 것처럼
함수 안에 함수를 선언하는 것도 가능

리턴값으로 함수를 리턴할 수도 있음

객체 리터럴을 하나 만든다

const obj = {add: add}

add 라는 키의 값이 add() 함수

<script>
    function outer() {
        const arr = []

        function add(todo) {
            arr.push(todo)
            console.log(arr)
        }

        const obj = {add: add}
        
        return obj

    }
</script>
<script>
    function outer() {
        const arr = []

        function add(todo) {
            arr.push(todo)
            console.log(arr)
        }

        const obj = {add: add}

        return obj

    }

    const todoService = outer()

    console.log(todoService)

</script>

todoService 안에 add가 들어 있다.

arr 이라는 변수는 외부에서 접근이 안 됨
outer.arr로 접근 못 함
이 arr 이라는 변수는 가려져 있음. 절대 못 봄. 진정한 접근 제한.
arr 이라는 변수는 보물창고
이 arr에 접근할 수 있는 건 outer를 실행해서 나온 함수. add 함수(문지기)만 접근이 가능.
이런 식으로 자바에서 클래스 만들어서 썼던 거를 자바스크립트에서 흉내를 낸 거

outer 함수의 실행 결과를 todoService에 넣음

const todoService = outer()

todoService에 있는 add 함수 호출

todoService.add()

마치 배열.push() 하는 것처럼

<script>
    function outer() {
        const arr = []

        function add(todo) {
            arr.push(todo)
            console.log(arr)
        }

        const obj = {add: add}

        return obj

    }

    const todoService = outer()

    console.log(todoService)

    todoService.add("AAA")
    todoService.add("BBB")
    todoService.add("CCC")
 
</script>

배열 안에 계속 내용물이 쌓이는 게 보임. 함수인데 상태를 유지하게 됨.

자바는 배열 쓰면 매우 어려움

arr에 접근할 수 있는 건 add 같은 문지기 밖에 없음
function을 통해서만 접근 가능
outer 함수의 실행 결과를 todoService 변수에
todoService를 통해서만 데이터 처리 가능

function removeTodo(num) 추가
특정 todo 삭제니까 매개변수 받기

<script>
    function outer() {
        const arr = []

        function add(todo) {
            arr.push(todo)
        }

        function removeTodo(num) {
            console.log("remove Todo....")
        }

        const obj = {add: add, removeTodo: removeTodo}

        return obj

    }

    const todoService = outer()

    console.log(todoService)

    todoService.add("AAA")
    todoService.add("BBB")
    todoService.add("CCC")

</script>

조회 하는 기능 추가
function getTodo(idx) 추가

const obj = {add: add, removeTodo: removeTodo, getTodo: getTodo}

변수명만 넣어줘도 자동으로 키 값, 키 값, 키 값으로 됨

↓ 변수명만 넣는다

const obj = {add, removeTodo, getTodo}

이제 todoService는 기능이 3가지가 됨

<script>
    function outer() {
        const arr = []

        function add(todo) {
            arr.push(todo)
        }

        function removeTodo(num) {
            console.log("remove Todo....")
        }

        function getTodo(idx) {
            console.log("get Todo....")
        }

        const obj = {add, removeTodo, getTodo}

        return obj

    }

    const todoService = outer()

    console.log(todoService)

    todoService.add("AAA")
    todoService.add("BBB")
    todoService.add("CCC")

</script>

이제 todoService는 기능이 3가지가 됨
내부적으로 어떻게 동작하는지 안 보임

전체 배열을 가져오는 기능도 추가하자

function getAll() 추가
getAll() 해서 배열 가져온 걸로 화면에 쫙 뿌려주면 됨

<script>
    function outer() {
        const arr = []

        function add(todo) {
            arr.push(todo)
        }

        function removeTodo(num) {
            console.log("remove Todo....")
        }

        function getTodo(idx) {
            console.log("get Todo....")
        }
        
        function getAll() {
            return arr
        }

        const obj = {add, removeTodo, getTodo, getAll}

        return obj

    }

    const todoService = outer()

    console.log(todoService)

    todoService.add("AAA")
    todoService.add("BBB")
    todoService.add("CCC")

</script>

로컬 스토리지에 저장해놨다가 꺼내서 쓰는 걸 만들 수도 있음

outer 함수를 별도의 자바스크립트 파일로 빼주면 좀 더 깔끔하게 쓸 수 있음

outer 함수를 별도의 자바스크립트 파일로 외부로 빼주면 깔끔하게 쓸 수 있음

자바스크립트 파일에서 데이트를 핸들링
html에서는 이벤트 처리하고 데이터 출력하는 게 일반적인 패턴

todo2.js

day6/todo2.js

todo2.js 생성해서 outer 함수 잘라내서 붙여넣기

todo2.html에 script 태그 추가
<script src="todo2.js"></script>

// todo2.html
<script src="todo2.js"></script>

<script>

    const todoService = outer()

</script>

영화번호 idx

어제 했던 영화 추가하는 함수 index.html ↓

todo2.js ↓

<script src="todo2.js"></script>
<script>

    const todoService = outer()

    todoService.add({title: "JS복습"})
    todoService.add({title: "Java공부"})

    console.log(todoService.getAll())


</script>

todo2.html ↓

<style>
    .panel {
        width: 100%;
        height: 50%;
        background-color: #badbcc;
    }

</style>

우리가 %를 준다고 제어되는 게 아님

픽셀을 쓰면 되잖아요

해상도

어디서는 맞고 어디서는 깨짐

viewport

카메라 뒤에 조그만 구멍

창 전체를 뷰포트로 본다
렌더링 하는 역영을 뷰포트라고 본다

실제 화면 사이즈를 계산해서 보여줌

두 가지 단위가 있음
vh 높이
vw 넓이

display: flex + viewport 사용

<style>
    * {
        margin: 0;
        padding: 0;
    }

    .panel {
        width: 100vw;
        height: 50vh;
        background-color: #badbcc;
    }

</style>

메뉴 상단바? 만들기

href 태그를 걸어서 스크롤 이동하게 해준다

메뉴 추가됨 ↓

겹쳐서 보임.. ↓

display: block
display: inline

label은 inline

심플 사이드바

이제 자바스크립트 처리 해야 됨

버튼 생성

    <div>
        <label>저장</label>
        <button>Save</button>
    </div>

버튼을 클릭하면

인라인 스타일로 이벤트 추가

    <div>
        <label>저장</label>
        <button onclick="saveTodo()">Save</button>
    </div>

onclick 권장되는 방법은 아님
옛날에 쓰는 방식임

value 값 읽어와야 됨

input value 값 읽어와야 됨

name 이라는 애를 이용해서 가져온다

("input[name='title']")

콘솔창에 태그들이 제대로 출력되는지 확인

value 값 얻어와야 됨

value 값 미리 넣어주기

    function saveTodo() {
        const titleEle = document.querySelector("input[name='title']")
        const contentEle = document.querySelector("textarea[name='content']")
        const dueDateEle = document.querySelector("input[name='dueDate']")

        console.log(titleEle, contentEle, dueDateEle)

        const title = titleEle.value
        const content = contentEle.value
        const dueDate = dueDateEle.value

        console.log(title, content, dueDate)
    }

이제 todoService에 객체 만들어서 넣어줘야 됨
todoService 안에 넣어줘야 됨

const complete = false 끝냈는지 여부

todoService.add({title, content, dueDate, complete})

들어갔는지 확인하고 싶으면 todoService.getAll() 함수 실행

제대로 들어갔는지 확인
console.log(todoService.getAll())

arr에 추가된 todo 항목들 출력됨

4교시 시작

이제 화면에 뿌려주는 작업 해야 됨

화면의 모양

체크박스

메일창?

한꺼번에 체크해서 한꺼번에 끝내는 거

번호를 순차적으로 하면 제일 처음 등록한 게 제일 밑으로 가게 됨

댓글은 순차적

일반적으로 게시글은 역순으로 최신글이 제일 위쪽으로 나오게

체크박스, 번호, 제목, 날짜

체크박스 전체선택
이게 좀 어려움
한꺼번에 이벤트를 처리하는 개념을 알고 있어야 됨
이벤트 버블링, 이벤트 캡처링

목록을 만들어서 뿌릴 건데 두 가지 방법 있음
1, table
2. ul, li

html 배우면 가장 먼저 나가는 숙제가 html로 이력서 만들기

th : table header
tr : 행
td : 열

    <h1>LIST</h1>
    <table>
        <thead>
            <td>전체선택</td>
            <td>번호</td>
            <td>제목</td>
            <td>날짜</td>
        </thead>
        <tbody>
            <tr>
                <td><input type="checkbox" name="complete"></td>
                <td>1</td>
                <td>AAAAA</td>
                <td>2021-12-22</td>
            </tr>
        </tbody>
    </table>

배열 데이터를 화면에 뿌려주는 함수

showList() 함수 생성

todo 리스트를 보여주는 함수

todoService에 add를 하면 목록을 새로 뿌려줘야 됨

saveTodo() 안에 showList() 추가

    function showList() {
        const todoArr = todoService.getAll()
        for (let i = 0; i < todoArr.length; i++) {
            const temp = todoArr[i]
        }
    }

temp 하나가 todo 하나

temp.idx or todoArr[i].idx

temp가 todo 한 건을 의미하는 거
temp에서 idx값도 꺼내와야 되고 title값도 꺼내와야 되고 dueDate값도 꺼내야 되고

예전에는 이렇게 했음
const title = temp.title
이런 식으로 4개 다 써야 됨

이거를 한 번에 처리할 수 있음

todoArr[i]에서 idx, title, dueDate, complete 끄집어 낼 거
todoArr[i] 하나를 다 분해해서 변수에 자동으로 할당해줌

const {idx, title, dueDate, complete} = todoArr[i]

다 분해해서 변수에 할당해줌 (구조분해 할당)

'js 구조 분해 할당' 검색

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

배열도 가능함

배열이나 객체의 속성을 해체해서 개별 변수에 담을 수 있게 하는 자바스크립트의 표현식이다.

자바에는 이 문법이 없음

배열의 개수만큼 tr 태그가 생김

tr 태그 하나가 todo 하나

let str = ''

    function showList() {
        const todoArr = todoService.getAll()

        let str = ''

        for (let i = 0; i < todoArr.length; i++) {
            const {idx, title, dueDate, complete} = todoArr[i] // 구조 분해 할당

            console.log(idx, title, dueDate, complete)

            str += `<tr>
                <td><input type="checkbox" name="complete"></td>
                <td>1</td>
                <td>AAAAA</td>
                <td>2021-12-22</td>
            </tr>`

        }

        console.log(str)

        document.querySelector("tbody").innerHTML = str
    }

    function showList() {
        const todoArr = todoService.getAll()

        let str = ''

        for (let i = 0; i < todoArr.length; i++) {
            const {idx, title, dueDate, complete} = todoArr[i] // 구조 분해 할당

            console.log(idx, title, dueDate, complete)

            str += `<tr>
                <td><input type="checkbox" name="complete" ${complete? 'checked':''}></td>
                <td>${idx}</td>
                <td>${title}</td>
                <td>${dueDate}</td>
            </tr>`

        }

        console.log(str)

        document.querySelector("tbody").innerHTML = str
    }

이벤트 버블링, 캡처링

체크박스 전체선택 하는 거 해보자

전체선택을 하려면 이벤트 버블링, 이벤트 캡처링 개념이 필요함

조회를 한다고 생각해보자

제목에 링크가 있다고 가정
제목을 클릭하면 조회한다고 가정
하나하나 다 이벤트를 거는 건 무식한 방법

첫 번째는 이벤트가 안 걸림
document.querySelector로 찾는 다음 addEventListener로 이벤트를 건다
근데 문제는
이 문서가 처음에 로딩될 때
문제는 얘네들은 새로 만들어진 애들
새로 추가하면서 만들어진 애들
이벤트를 거는 당시에 이 element는 DOM에 없다
tr이라는 애가 새로 생기는데
tr이 생기기 전에 이벤트를 걸면 tr이 없는 거
그럼 당연히 이벤트가 안 걸림
아무리 클릭해봤자 이벤트는 걸리지 않음

querySelectorAll()
https://developer.mozilla.org/ko/docs/Web/API/Document/querySelectorAll
배열로 반환됨

const trArr = document.querySelectorAll("tbody tr")

addEventListener 쓸 때 맨날 false 쓰는 이유

AAA 나옴

document.querySelector("tbody tr")
querySelector()는 여러 개 있으면 제일 첫 번째거 반환

BBB 나옴

근데 새로 추가된 애들 클릭하면 안 걸림

이벤트를 걸 때는 tr이라는 애가 없었음
새로 만들어진 tr
그러니까 이벤트가 못 걸린 거
이런 애는 이벤트를 어떻게 걸어야 하지?
이 문제를 처리하는 방법 2가지 있음
1. 간단하고 편한 방법
2. 조금 복잡한 방법

버블링, 캡처링

이거를 잘 이해하고 쓰면 이벤트 숫자를 줄일 수 있음

나중에 제이쿼리

제이쿼리는 이런 처리가 잘 되어 있음

전부 클릭하면 alert창 뜨게 이벤트 걸어줌

alert창이 어떤 순서로 뜰까

가장 안쪽에 있는 btn부터 뜬다
그 다음 d3
그 다음 d2
그리고 d1 뜸

지금 클릭한 건 btn인데 감싸고 있는 애들까지 이벤트 다 실행됨
이벤트가 퍼져나감
이거를 '이벤트 전파'라고 함
안쪽에 있는 애가, 대놓고 클릭한 애가 제일 먼저 동작하고
그리고 걔를 감싸고 있는 애가 동작하고
점점 위로 올라감
거품이 피어오르는 것 같다고 해서 '버블링'이라고 표현한다

반대로 클릭하면 d1부터 d2, d3, btn이 찍히는 방식을 '캡처링' 방식이라고 한다.

이벤트 버블링
이벤트 캡처링

대부분의 브라우저는 버블링 방식을 사용

안쪽에서 바깥쪽으로 피어오른다고 생각하면 됨

가끔가다 어떤 브라우저가 캡처링 방식을 사용할 수도 있음
우리는 캡처링은 지원 안 해, 우리는 버블링만 쓸 거야~
그게 바로 false임

addEventListener() 쓸 때 마지막에 false라고 파라미터 주는 거
그 의미가 나는 캡처링 방식은 안 할 거야. 나는 버블링 방식만 할 거야

자바스크립트는 함수는 함수의 파라미터 개수 안 맞아도 호출이 되는데 왜 계속 false를 입력했을까
false 안 줘도 동작은 함

이벤트를 걸 때는 false를 반드시 쓰는 게 기본임

addEventListener() 쓸 때 반드시 false를 붙여줘서 캡처링을 막자

이벤트에서 가장 중요한 메소드 2가지
이벤트는 기본적으로 정보다
이벤트는 기본적으로 객체다
이벤트 안에는 여러 개의 정보가 있음
접근하고 싶으면 점으로 타고 타고 접근하면 됨
이벤트는 전파가 된다
내가 버튼을 클릭하면 나는 BTN 이란 메시지만 나오게 하고 싶고 나머지는 클릭 안 걸렸으면 좋겠어
그럴 때 쓰는 게
나는 BTN이라는 것만 실행됐으면 좋겠어
더 이상의 전파를 막는 거

propagation : 전파

stopPropagation() : 이벤트 전파를 막는다.

이벤트 전파를 막아버림

e.stopPropagation()

BTN만 뜨고 끝남

preventDefault() : 기본 동작을 막는다.

e.preventDefault()

default를 막는다

태그마다 기본적인 동작이 있음. 그걸 막는다는 거.

네이버로 이동한다

이게 a 태그의 기본 동작

a 태그의 기본 동작은 이동

form 태그의 기본 동작은 submit

근데 preventDefault()

네이버로 이동 안 함

왜 이 책에는 그런 설명이 없는가

웹 페이지를 만들고 싶은 사람이 보는 책

우리 수업은 웹 어플리케이션이 어떤 형태일 것인가

예전에는 html이 데이터고 자바스크립트는 보조하는 역할이었다

프론트엔드 어플리케이션에서는 자바스크립트가 데이터를 가지고 있고 html이 뷰어 역할을 하는 주객이 전도된

동적으로 만들어진 애들
이벤트가 걸 수가 없다
이벤트를 걸려면 다른 방법을 써야 된다
2가지 방법이 있음
1. 원래 있던 애한테 이벤트를 걸고
tbody는 원래 존재했음
원래 있던 element한테 이벤트를 걸고
e.target 실제 이벤트가 발생한 요소(객체)를 찾아서 핸들링하는 방법

클릭

첫 번째는
이벤트는 target이라는 애가 있어서
실제 이벤트가 발생한 요소를 찾아서 뭔가 핸들링 할 수 있는 방법

­2.
두 번째는
배열을 루프 돌리면서 동적으로 생성할 때 onclick을 줘버리는 방법
루프 돌릴 때 onclick을 줘버리는 방법
이게 훨씬 쉽긴 함
너무 많음
이벤트 하나하나 절대 못 검

바깥쪽에서부터 이벤트를 걸 수 있다는 사실 정도는 알고 있어야 됨

브라우저에서 딥러닝 돌릴 수 있음

얼굴 인식

머신 러닝

자바스크립트는 지구 정복중

타입스크립트까지

내년에는
앱 flutter
스프링은 스프링부트
리액트
웹은 서버에서 뿌리는 것보다

체크박스 전체선택 함수 만들기

­1. 화면에서 제어 하는 방법
2. 데이터를 제어 하는 방법 (O)

어차피 뿌려지는 건 데이터니까
데이터의 complete 값을 다 바꾼 다음 다시 뿌리는 거

본질은 결국에 데이터

const complete = true

complete를 바꿔주고 그 데이터를 다시 뿌려줄 거

function changeAll() {
        
}

changeAll()

일단 다 바꾸는 걸로

    function changeAll() {
        for (let i = 0; i < arr.length; i++) {
            arr[i].complete = !arr[i].complete
        }
    }

changeAll 추가해 주기

const obj = {add, removeTodo, getTodo, getAll, changeAll}

todo2.html에 checkAll() 함수 생성 ↓

// todo2.html
    function checkAll() {
        todoService.changeAll()
        showList()
    }

특정한 애 삭제

삭제 버튼 만들자

idx가 유니크한 값이니까 idx로 삭제하는 걸로

삭제하고 showList() 실행

    function deleteTodo(index) {
        confirm("deleteTodo?")

        todoService.removeTodo(index)
        showList()
    }

삭제한다는 건 배열에서 뺀다는 의미

button에서 onclick으로 함수 호출

표준은 아님

addEventListener()를 쓰는 게 좋음

그 함수에 idx값을 줘야 됨

idx번호를 받아서 호출해야 되는데

<td>${title}<button onclick="deleteTodo(${idx})">DEL</button></td>

idx가 num이 아닌 애들만 걸러내면 됨
거르는 조건이
idx값이 num값이 아닌 애들만 걸러내서 남겨놓는다
걔네들이 다시 배열이 되는 거

todo.idx가 num이 아닌 것들

// todo2.js
    function removeTodo(num) {
        console.log("remove Todo....")

        const result = arr.filter(todo => todo.idx !== num)

        arr = result
    }

클로저: 함수를 상태 유지 → Java 클래스 - 인스턴스
돼지저금통

데미지를 받을 거

this

자바에서 만드는
데이터와 로직을 같이 가지고 있는 존재가 자바의 클래스

자바스크립트는 그렇지가 않아
함수와 변수 밖에 없음

함수가 끝나고 나면 그 안의 모든 변수가 사라지는데 (지역변수)
어떤 계기로 인해서 자기의 바깥쪽에 있는 데이터를 가리키고 쓰고 있는 거
그 참조 현상을 클로저라고 한다

거기 있는 변수 자체를 쓰는 게 아니라 그 공간을 참조하는 거

i 값 자체를 복사해서 가지고 있는 게 아니라 공간을 참조하고 있는 것 뿐

감춰진 참조

40초 정도
개념
나의 경험 (프로젝트 어디어디에 클로저를 써야 될 일이 있었다)
나의 느낌 (썼더니 어떤 점이 좋았고 어떤 게 헷갈렸다)

자바스크립트에서는 '모듈 패턴'이라고 한다
클로저를 쓰는 가장 대표적인 패턴
내부에 상태를 가지게 하고 상태를 조작하는 함수들을 반환

상태라는 게 보물창고
상태는 조작하는 애들이 문지기

보물은 함수의 안쪽에 변수로 선언되어 있다
외부에서 다이렉트로 접속할 수 없다

데이터를 다루는 애를 service 라는 이름으로 빼버림

클로저

event → 버블링/캡쳐링

stopPropagation() : 이벤트 전파를 막는다
preventDefault() : 기본 동작을 막는다 (예: a 태그 이동 막는다)

이벤트를 걸 수 없는 상황
이벤트 처리 시에는 DOM에 없었는데
작업을 하면서 추가되는 애들
동적으로 생성이 된 애들한테는 이벤트가 안 걸린다
그럴 때 가장 쉽게 하는 방법이 onclick
제이쿼리에서는 조금 더 깔끔하게 처리할 수 있음

target : 실제로 이벤트가 발생한 element (태그)

e.target

실제로 이벤트가 어디서 발생했는지 알고 싶음

이게 좀 더 깔끔한 방법이긴 함

구조분해 할당

전개 연산자라는 것도 있는데 이건 나중에 하겠음

0개의 댓글