클래스란 설계도이고 인스턴스는 설계도를 이용해 만든 작품을 뜻한다.
예시로 생각하는게 편한데, 현대자동차 그룹이 클래스이고, 거기서 생산된 아반떼, 제네시스가 인스턴스라고 생각하면 된다.
좀 더 있어보이게 표현하면 하나의 모델이 되는 청사진을 클래스라 하고, 그 청사진을 바탕으로 한 객체를 인스턴스라 한다.
기본 코드 뼈대는 다음과 같다.
class Car {
constructor(brand,name,color){
this.brand = brand
this.name = name
this.color=color
}
method(){
console.log(`${brand}의 ${name}은 무엇이다.`)
}
}
let Genesis = new Car('Genesis','mycar','black')
영어로는 recursive라 하며
주어진 문제를 비슷한 구조의 가장 작은 문제 단위로 쪼갤 수 있을 때 사용하는 개념이다.
중첩된 반복문이 많은 경우에도 유용하다.
문제를 보고 재귀로 풀어야겠다 라고 생각할 수 있어야 하는데
이 때 재귀적 사고가 필요하다.
기본적인 재귀적 사고
function arrSum(arr){
//base case : 더 이상 쪼갤 수 없을 때 = 재귀 탈출 조건 작성
if(arr.length === 0){
return 0
}
//recursive case : 문제를 계속 쪼개는 과정을 작성
return arr[0] + arrSum(arr.slice(1))
네트워크를 통해 데이터를 주고 받을 때 정해진 형식이 있는데 그것은 바로 JSON 형태로 전송하는 것이다.
이 때 전송을 위해서는 JSON 형태로 변경해야 한다고 형님들이 말씀하셨다. 그냥 받아들이자.
전송가능한 조건은
JSON.stringify()
: 객체타입을 JSON 형태로 변환한다.
JSON.parse()
: JSON 형태 자료를 객체타입으로 변환한다.
stack은 데이터를 순서대로 쌓는 자료구조다.
FILO이라고도 하는데 먼저 들어온 요소가 가장 마지막에 나가는 구조를 가진다.
stack을 활용한 문제풀이는 꽤나 많은데,
최근에 풀었던 문제들 중에서는 병합정렬 문제,브라우저 뒤로가기 앞으로가기 문제가 있었다. 다시 풀어봐야겠다.
queue는 FIFO으로 먼저 들어온 요소가 가장 먼저 나가는 구조를 가진다.
최근에 풀었던 문제는 박스포장, 프린터, 병합정렬, 연결된 정점들 문제가 있었다. 다시 풀어봐야겠다.
graph는 크게 이진탐색트리와 순회가 있었다.
이진탐색트리는 시간복잡도가 O(logN)을 가진다.
왼쪽부터 탐색하는 특징을 갖고 있고, 배열을 가운데를 중심으로 좌,우로 나눠 해당 배열에 찾는 요소가 있는지 탐색하는 방법이다. UP&DOWN 게임이라 생각하면 편하다.
대표적인 이진탐색 코드는 다음과 같다.
const binarySearch = function (arr, target) {
let left = 0,
right = arr.length - 1;
while (left <= right) {
let middle = parseInt((right + left) / 2);
if (arr[middle] === target) {
return middle;
}
if (target < arr[middle]) {
right = middle - 1;
} else {
left = middle + 1;
}
}
return -1;
};
트리순회는 트리의 모든 노드를 한 번씩 방문하는 것을 말하는데, 전위 순회, 중위 순회, 후위 순회가 있다.
전위 순회는 왼쪽 트리를 중심으로 탑다운으로 순회하는 구조를 말하고,
중위 순회는 왼쪽 트리를 중심으로 맨 아래 트리 부터 순회하며 올라오는 구조를 말한다.
후위 순회는 중위 순회와 비슷하지만 왼쪽 트리 순회가 끝나면 루트를 거치지 않고 오른쪽 노드로 넘어가는 특징이 있다.
동기는 진행 중인 작업 끝나면 그 다음 작업이 진행되는 것을 말한다.
하지만 비동기는 동시에 작업을 진행할수도, 작업속도를 지연시킬 수도 있는 상태를 말한다.
동기적인 요소들은 call stack에 쌓여있다가 바로 실행되는 반면, 비동기적인 요소들은 task queue에 전달되었다가 call stack이 비면 가져오는 방식을 사용한다.
console.log('1')
setTimeout(() => {
console.log('4');
},1000)
console.log('2')
console.log('3')
이것을 작성했을 때 크롬은 어떻게 작동하는가?
4가 출력되기 전에 2와3이 먼저 출력된다.
웹 브라우저는 내가 작성한 js코드를 실행해주는 애들
웹 브라우저 안에는 stack이 있는데 내가 작성한 코드를 실행해주는 곳이고 오직 한곳만 존재한다. -> 싱글 스레드
여기서
setTimeout(() => {
console.log('4');
},1000)
은 바로 실행되는 코드가 아니라서 stack에 두지 않고 대기실인 queue에 저장한다.
queue에 저장되는 대표적인 코드는 Ajax,이벤트리스너,setTimeout 등 기다림이 필요한 코드들은 여기로 저장된다.
여기서 stack이 완전히 비었을 때 queue에서 바로 stack으로 이동해 출력된다.
console.log('1')
setTimeout(() => {
console.log('4');
},1000)
console.log('2')
console.log('3')
setTimeout이 0초로 주어진다 해도 바로 실행되지 않고 queue로 이동한 후 stack이 비었을 때 출력된다.
만약 js로 10초걸리는 어려운 연산을 실행시킨다고 하자.
이 때 Ajax요청, 이벤트리스너 같은 비동기요청을 하면 stack이 10초동안 연산 중이기 때문에 그 과정이 끝날 때 까지 queue에서 대기해야 한다. 따라서 10초동안 유저는 외부 API를 통해 영화목록을 가져오거나, 모달창을 띄우는 버튼클릭을 할 수 없게 된다
stack 바쁘게 하지말자.
queue를 바쁘게 하지 말자. (모달창 1000개 띄우기)
우선 네트워크에 대해 알 필요가 있다.
크게 클라이언트와 서버 2 Tier로 구성되어있다.
클라이언트(유저)에서 데이터를 요청하면 서버에서 필요한 데이터를 전송해준다. 이것이 큰 틀이다.
클라이언트는 웹사이트, 스마트폰, 태블릿용 앱, 데스크톱 앱 으로 구분할 수 있다.
이렇게 클라이언트와 서버가 통신하기 위해선 프로토콜(규약)을 지켜야하는데 중 하나가 HTTP다.
주요 프로토콜은 HTTP,HTTPS,FTP,SMTP,SSH,RDP,Websocket,TCP,UDP 까 있다.
그렇다면 API는 무엇일까? 클라이언트가 서버에 데이터를 요청할 떄 HTTP라는 프로토콜을 통해 요청하는데, 여기서 요청하는 양식을 뜻한다.
이 양식은 백엔드 엔지니어가 직접 작성하는 것이며,
작성된 API 문서를 사용 시 정해진 양식을 정확히 사용해야 한다.
/coffee/americano?quantity=2&syrup=hazelnet
위 API 양식에서 확인할 수 있는 것은 URL,URI 이다.
프로토콜을 HTTP로 사용한다 했을 시, 엔드포인트에 들어있는 요소는 scheme,hosts,url-path 다.
http://www.google.com:80/search
URI는 URL이 포함하는 scheme,hosts,url-path에 더해 query,bookmart를 포함한다.
http://www.google.com:80/search?q=JavaScript
우리가 google를 검색할 때 www.google.com이라고 명확히 구글사이트임을 알 수 있는데, 이는 도메인을 사용했기 때문이다. 모든 주소가 도메인을 갖고있는 것은 아니며 도메인 검색 시 매칭되는 실제주소가 있는지를 탐색한다.
HTTP를 통해 서버에 데이터를 요청할 떄 API의 양식을 따른다고 했다. 그럼 여기서 요청하는 메소드는 무엇이 있을까
get/post/put/delete/options/patch가 있다.
Express는 Node.js의 프레임워크로 클라이언트-서버 간 데이터전송 코드를 한 층 간결하게 작성할 수 있게 도와준다.
express없이 데이터 요청 및 전송 코드를 작성한다면 다음과 같다.
const server = http.createServer((request, response) => {
if (request.method === 'POST') {
let body = []
request
.on('data', (chunk) => {
body.push(chunk)
})
.on('end', () => {
// body = Buffer.concat(body).toString()
response.writeHead(201, defaultCorsHeader)
if (request.url === '/upper') {
response.end(body.toUpperCase())
}
express를 사용하면 간결하게 코드를 작성할 수 있다.
app.post('/upper',function(req,res)=>{
res.json(body).toUpperCase()
express는 라우팅 즉 특정한 HTTP 메소드 요청을 분기점으로 나누어 작성하는데, 메소드와 url를 정확히 적어 그것이 일치할 때 응답이 가능토록 한다.
미들웨어는 라우팅이 실행될 떄 자동으로 실행되게 하는 함수를 뜻한다.
app.post('/upper', function (req, res) {
const { body } = req
console.log((body).toUpperCase())
res.json((body).toUpperCase())
})
const myLogger = function (req, res, next) {
console.log(req.method, req.url);
if (req.method === 'DELETE') {
res.send('잘못된 요청')
}
next()
}
app.post('/lower:id', function (req, res) {
console.log(req.params)
const { body } = req
console.log((body).toLowerCase())
res.send((body).toLowerCase())
})
myLogger라는 미들웨어 함수에 next()를 실행하면,
myLogger보다 위에 있는 라우팅을 실행하게 되면 미들웨어가 실행되지 않고, 아래 라우팅을 실행하면 미들웨어가 실행된다.
React의 단방향 데이터 흐름을 이용해 자식컴포넌트에서 상태변경함수가 실행되면 부모컴포넌트에 있는 상태가 변화하는 방식이다.
주로 이벤트를 자식 컴포넌트에 props할 때, 자식은 해당 props를 받아서 콜백함수 형태로 사용한다.
그렇게되면 해당 이벤트가 실행될 때 부모 컴포넌트에 있는 이벤트가 실행된다.
useEffect는 대표적인 side effect인 Ajax,setTImeout, 이벤트리스너를 자동으로 실행하게 하는 함수다.
useEffect(()=>{
실행시킬 비동기함수
},[상태함수])
useEffect의 두번째 인자가 상태함수로 들어간다면, 해당 상태함수가 변경될 때 useEffect가 실행된다.
빈 배열로 들어간다면 화면에 렌더링 될 때 한번 실행되고 그 다음부터는 실행되지 않는다. -> Ajax를 한번 요청할때 이걸 쓰면 유용할 것이다.
장바구니 웹사이트를 구현하면서 리덕스의 필요성을 느꼈다.
함수를 App.js에서 자식컴포넌트로 게속 props를 하는것도 귀찮고, 현업에서 수많은 자식컴포넌트가 있을 때 모두 props를 하기는 현실적으로 불가능할 것이라는 생각이 들었다. 따라서 redux를 이용해 store에 저장된 함수들을 필요한 컴포넌트에서 사용할 수 있도록 하는 것이 좋다는 것을 코드를 작성하며 느낄 수 있었다.
먼저 어떤 상태를 변경할지를 명시하는 aciton을 작성한다.
export const addToCart = (itemId) => {
return {
type : ADD_TO_CART,
payload : {
quantity : 1,
itemId
}
}
}
이를 reducer 함수로 전달한다.
const itemReducer = (state,action) => {
switch (action.type) {
case ADD_TO_CART :
return Object.assign({},state, {
cartItems : [...state.cartItems,action.payload]
})
default;
return state;
}
}
그 다음 useSelector를 이용해 itemReducer를 가져온 후 dispatch를 통해 필요한 액션을 실행시켜 상태변경을 시킨다.