diff --git a/commerce/README.md b/commerce/README.md new file mode 100644 index 0000000..4fe9f34 --- /dev/null +++ b/commerce/README.md @@ -0,0 +1,51 @@ +## 고객 활동 로그 분석 + +커머스 필드에서 고객의 활동을 분석하는 것은 매출로 이어지기에 고객의 행동을 여러 각도에서 분석하는 것은 중요하다. +야래의 내용은 네이버 스마트 스토어와 고도몰(NHN 쇼핑몰 제작 플랫폼)에서 트래킹하여 사용자들에게 제공하는 요소들이다. + +- 고객 데이터: 스토어의 고객 현황 (주문 고객 통계, 성별/연령대/고객 등급간 구매 통계, 재구매 통계) +- 마케팅 분석: 유입이 발생한 마케팅 채널 통계, 마케팅 채널 성과, 키워드별 유입 및 결제 성과 +- 쇼핑행동 분석: 페이지/상품별 고객의 주요 행동 데이터(유입 고객 수, 체류 시간, url / 상품 상세 조회 수, 상품 ID, 상품명, 결제 상품 수량) +- 실시간 분석: 1시간 단위의 스토어 거래 정보를 실시간으로 제공 +- 판매 분석: 배송 통계, 판매 성과, 상품별 결제 데이터 + +![image](https://github.com/user-attachments/assets/376ef164-8264-4e4e-ace8-8029e63538ef) + +### 고객 활동 분석을 돕는 툴로 GA(Google Analytics), GTM(Google Tag Manger)들이 있는데, 이 둘의 차이를 짚어보자. + +### GTM + +![img](https://github.com/user-attachments/assets/e1e5e2ee-ea1d-4742-bea8-59882d0b0273) + +- GTM 스크립트를 삽입한 뒤, GA 혹은 다른 툴로 연결한다. +- 여러 툴(GA, Facebook 등)을 사용할 수 있게 해주는 중간 다리 역할을 한다. +- GA와 같은 여러 툴(도구)들을 관리할 수 있게 해준다. +- GA에 자바스크립트 추적 코드(= 태그라고도 함)를 쉽게 추가하고 규칙을 정의할 수 있다. +- 사용 목적 + - 자바스크립트 추적코드 관리 가능(GA는 이 심어진 코드를 바탕으로 분석 보고서를 제공한다.) + +### GA + +![Google Analytics](https://github.com/user-attachments/assets/fb9aa3bc-bcda-419d-981c-ff2b6124e182) + +- GA 스크립트, 로그 수집 코드를 삽입할 수 있다. +- 유입 및 행동 레포트에 따라 목표 전환이 가능하다. +- 태그를 개발자가 삽입해야한다. +- 사용 목적 + - 웹 사이트 방문자 수, 방문자의 접속 지역 파악 + - 세션 당 페이지 수, 이탈 수 파악 + - 가장 인기있는 페이지, 이벤트 파악 + - 접속한 기종(android, ios) 파악 + +### 정리 + +- GA - 사이트 활동에 대한 보고서를 제공하는 분석 도구 +- GTM - 정의된 규칙에 따라 추적 코드를 실행하는 도구 +- GTM과 GA는 서로 완전히 대체될 수 없다. +- 사용 목적이 아예 다르며, GTM은 GA 관리를 편하게 해줄 수 있는 툴이다. +- A/B 테스트나, 유의미한 데이터를 뽑기 위해선 GA를 이용해야한다. + +Cf) 참고 + +- https://mingg123.tistory.com/265 +- https://theanalytics.kr/8-%EA%B5%AC%EA%B8%80%ED%83%9C%EA%B7%B8%EA%B4%80%EB%A6%AC%EC%9E%90-gtm%EC%99%80-%EA%B5%AC%EA%B8%80%EC%95%A0%EB%84%90%EB%A6%AC%ED%8B%B1%EC%8A%A44-ga4-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%B0%A8%EC%9D%B4/ diff --git a/css/css_notepad.md b/css/css_notepad.md index db8cc88..d2a2b7a 100644 --- a/css/css_notepad.md +++ b/css/css_notepad.md @@ -1,4 +1,67 @@ ** css 상식 + - css와 sass(Syntatically Awesome Style Sheets) 차이 + + css를 사용해 style을 적용할 경우, + + 1. 선택자(Selector)를 지정할 때, 불필요한 부모 요소 선택자를 매번 적어야 한다. + + 2. 프로젝트 규모가 커져감에 따라 중복해서 수정해야 되는 부분이 늘어난다. 가령, 반복적으로 사용된 부모 요소 선택자의 이름이 변경 된 경우. + + 3. 연산 기능에 한계가 있다. + + 4. 구문이 존재하지 않는다. + + -> 따라서 sass는 css의 태생적 한계를 보완하기 위해 아래와 같은 기능을 제공한다. + + 1. 변수의 사용 + + 2. 조건문과 반복문 + + 3. import + + 4. 중첩(nesting) + + 5. mixin + + 6. extend / inheritance + + - word-break와 word-wrap의 차이 + + 이 정도까지 알아야 싶나 하지만, 혹시나 하는 마음에 어느정도 큰 틀만 알고 다음에 다시 보기 위해 해당 내용 관련해서 캡처한 것을 올린다. + + 참고 사이트: cf)https://wit.nts-corp.com/2017/07/25/4675 + + word-break 속성: + + ![image](https://user-images.githubusercontent.com/53415000/148174541-7ef24ee2-1588-4402-b762-cb344f2eb525.png) + + +
+ word-wrap 속성: + + ![image](https://user-images.githubusercontent.com/53415000/148174651-87321c04-a87c-4d0f-a82e-52fac866c9c9.png) + + 미세한 차이가 있는 듯하다. + + + - overflow-wrap: break-word vs word-break: break-word + + ![image](https://user-images.githubusercontent.com/53415000/148054710-437d9cfe-88df-4e64-9bdb-00cf77492887.png) + + 요약해서 정리하자면, + + - overflow-wrap: word-break (<=> break-words, tailwind에서 같은 표현) + + ![image](https://user-images.githubusercontent.com/53415000/148173454-68534762-d8a0-4cd3-b7a5-2e24a9bee215.png) + + - word-break: break-all(<=> break-all, tailwind에서 같은 표현) + + ![image](https://user-images.githubusercontent.com/53415000/148173592-974f5060-aa95-49a8-b6ec-e0a81ecb9609.png) + + + - word-wrap: word-break + + - self-start(<=> align-self: flex-start) diff --git a/feconf/component.md b/feconf/component.md new file mode 100644 index 0000000..147dae6 --- /dev/null +++ b/feconf/component.md @@ -0,0 +1,25 @@ +

컴포넌트, 다시 생각하기


+
+ +
+
+ + 질문정답보다 중요하다.
+
+ + 관점기술보다 중요하다. + +
+
+ + * Coponent 설계 시 Principle + + 1. 비슷한 관심사는 가까운 곳에(co-location) + + 2. 데이터를 ID 기반으로 정리하기 + + 3. 의존한다면 의존성 그대로 드러내기 + + 4. 모델 기준(리모트 데이터)으로 컴포넌트 분리하기 + +cf) 보다 자세한 내용은 블로그에 정리해놓았습니다.
https://searching-power.tistory.com diff --git a/functionalProgramming/readme.md b/functionalProgramming/readme.md new file mode 100644 index 0000000..cd340ff --- /dev/null +++ b/functionalProgramming/readme.md @@ -0,0 +1,58 @@ +* 함수형 프로그래밍 + + +니콜라스의 영상을 보며 정리한 내용입니다. + + + - '함수형 프로그래밍'은 코드 작성 '스타일'이다. 함수형 프로그래밍 개념을 어떤 프로그래밍 언어에도 사용가능하다. + + - clojure와 scala는 아예 함수형 프로그래밍으로 설계된 언어이고 빌트인 기능이 있어 함수형 코드를 작성하기 쉽다.(cf, Clojure, F#, Elixir, Erlang) + + - 함수형 프로그래밍을 배우면, 프로그래밍 문제를 해결할 때 유용한 새로운 관점과 접근 방식을 얻을 수 있다. + + - 함수형 방식에서는 버그 자체가 발생하기 어렵다. + +
+* 왜 함수형프로그래밍이 좋을까? + + - 이 이유를 알려면 명령형(imperative) 코드, 선언형(declarative) 코드간의 차이를 살펴야 한다. + + - 선언형: 원하는 결과를 표현하기 위해 코드가 작성(ex, '토스트를 만들어줘') + + - 명령형: 원하는 결과를 얻기 위해 필쵸한 지침에 따라 코드가 작성(ex, '빵을 가져오고, 토마토를 가져오고, 햄을 가져와서 합쳐라') + + - 선언형 코드의 예시 + + - css는 선언형 언어(원하는 결과만 작성하면 된다.) + + - 선언형 코드는 원하는 결과값을 선언하는 것. / 명령형 코드는 결과값에 어떻게 도달하느냐에 관한 것. + + - js에는 선언형 코드 형태의 함수를 갖고 있다. filter, replaceAll 등과 같은. + + - 텍스트 문자열에서 공백을 제거하고, 다른 문자로 대체하는 작업을 한다고 가정한다고 할 경우, + + ``` + 명령형(imperative) 코드에서는 아래와 같이 작업 + function spaceToHeart(text) { + let result = ""; + for (let i=0; iParallelism is not the goal of concurrency, concurrency's goal is a good structure + + ``` + package main + + import ( + "fmt" + ) + + func main() { + woof() + meow() + } + + func woof() { + for i := 1; i <= 5; i++ { + fmt.Println("woof ", i) + } + } + + func meow() { + for i := 1; i <= 5; i++ { + fmt.Println("meow ", i) + } + } + + ``` + + * 위 코드에서는 woof 함수와 meow함수가 순차적으로 실행된다. 만약 parallel execution이 가능하게 하려면 `go` keyword를 명령어 바로 앞에다 붙여서 사용한다. + + ``` + go woof() + meow() + ``` + + * 위 함수의 실행결과는 어떻게 될까? 신기하게도 meow 함수의 결과만 출력된다. concurrency를 언급할 때, parallel lanes들이 있고, 각각의 명령들이 고유한 lane에서 다른 것들과 병렬적으로 실행되는 것으로 생각하곤 한다. 이 각각의 lane들은 흔히 말하는 goroutine이다. 순차적으로 실행시키는 코드에서는 각각의 함수(ex, woof, meow)가 main goroutine 하나에서 실행이 된다. + + * go woof()를 통해 새로운 goroutine을 만들었지만, 실행 결과가 출력이 되지 않았다. 이러한 이유는 woof가 실행되는 고루틴에서 출력을 print하기 전에, 메인 고루틴이 다음 명령어(meow)를 실행해버렸고 이후 meow 다음으로 실행될 항목이 없음을 확인하고 종료해버렸기 때문이다. 메인 고루틴이 종료되면 다른 모든 고루틴들을 자동으로 종료시키는 특성이 있다. 결론적으로 결과물이 출력이 안된 것은 print하기 전에 woof함수의 routine이 종료되었기 때문이다. + + * 그렇다면... 어떻게 하면 이러한 문제를 피할 수 있을까? + + * 그것은 바로... !, `WaitGroup`이란 것을 사용하는 것이다. + + * WaitGroup은 두 함수를 실행시키는데 필수적인 synchronization을 제공한다. 아래 코드를 참조해 이해보면 좋다. + + ``` + import ( + "fmt" + "runtime" + "sync" + ) + + var wg sync.WaitGroup + + func main() { + // add one thing to wait for + wg.Add(1) + go woof() + meow() + + // stop waiting when 0 things in waiting list + wg.Wait() + } + + func woof() { + for i := 1; i <= 5; i++ { + fmt.Println("woof ", i) + } + // remove one thing from waiting list + wg.Done() + } + + func bar() { + for i := 1; i <= 5; i++ { + fmt.Println("meow ", i) + } + } + ``` + + * 이제 프로그램을 실행하면, 두 함수의 결과를 모두 볼 수 있게 된다. + + * 무슨 일이 일어난 걸까? + + * woof 함수를 실행하기 전에, waiting list에 1 thing을 넣은 후에 프로그램은 woof 함수 실행을 위한 goroutine을 실행시킨다. 그리고 다음으로 실행할 명령어인 meow로 이동한다. 하지만 이번에는 프로그램을 끝내는 대신, waiting list가 빈 상태가 될 때까지 기다리게 하는 `wg.Wait()`을 마주하게 되었다. 위 코드에 woof 함수 내에 서 `wg.Done()`이 있는데, 이것은 기본적으로 프로그램에게 프로세스가 종료되었고 waiting list에서 나와도 된다는 것을 알려주는 것이다. + + + * 관련 posting이 2개 더 있는데 이거 관련 내용은 추후 작성하도록 하자. + + cf) https://dev.to/rinkiyakedad/concurrency-in-golang-45d4 + +### chatGPT's Answer about 'which is better go, nodejs' + + + + Both Go and Node.js are popular choices for building web applications and microservices, but they have different design philosophies and are better suited to different types of projects. + + Go, also known as Golang, is a statically-typed language that is designed to be simple, efficient, and scalable. It has a small number of core language features and a clean, minimalist syntax. Go was developed by Google specifically for building high-performance, concurrent systems, and it has excellent support for concurrency and parallelism. It's a good choice for building high-performance servers, networking services, and other low-level systems. + + Node.js, on the other hand, is built on top of JavaScript, and it's designed to be a flexible, easy-to-use platform for building web applications. Node.js has a large and vibrant ecosystem, with thousands of libraries and frameworks available to help you build anything from simple command-line tools to complex web applications. Node.js uses an event-driven, non-blocking I/O model, which makes it well-suited for building real-time, data-intensive applications, like chat, gaming and live-streaming. + + So, to sum up: + + Go is a good choice for building high-performance, concurrent systems, networking services, and other low-level systems. + Node.js is a good choice for building web applications, real-time and data-intensive applications, and other apps that require a lot of I/O operations. + The choice between the two languages depends on the specific requirements and the use-case of your project. + + + +[ memory leak of map ] + + * 다음 블로그를 참조하여 정리한 내용입니다. + + cf) https://teivah.medium.com/maps-and-memory-leaks-in-go-a85ebe6e7e69 + + - map은 메모리 상에서 항상 증가하며, 절대로 감소하지 않는다. 따라서 메모리 이슈를 초래한다면, map을 re-create 한다거나, pointer를 사용하는 방식으로 처리할 수 있다. + + ``` + m := make(map[int][128]byte) + + ``` + + - 위 코드로 다음의 상황을 가정해보자 + + 1) 빈 map을 생성하고, + + 2) 백만개의 요소를 add하고, + + 3) 이후 모든 요소를 제거하고 가비지 컬렉션이 작동되는 상황을 가정해보자. + + - 각각의 단계에서는 printAlloc이라는 utility function을 사용하여 size of heap을 출력한다. + + ``` + func main() { + n := 1_000_000 + m := make(map[int][128]byte) + printAlloc() // 1) output: 0mb + + for i := 0; i < n; i++ { // Adds 1 million elements + m[i] = [128]byte{} + } + printAlloc() // 2) output: 461mb + + for i := 0; i < n; i++ { // Deletes 1 million elements + delete(m, i) + } + + runtime.GC() // Triggers a manual GC + printAlloc() // 3) output: 293mb + runtime.KeepAlive(m) // Keeps a reference to m so that the map isn’t collected + } + + func printAlloc() {} + ``` + + - 위 코드에서 백만 개의 원소를 map에 넣었을 때, 461mb의 크기가 되었다가 이후, 모든 원소를 삭제하였을 때 map의 크기는 293mb가 된다. map 내에 백만 개의 요소가 있을 때보다 크기가 줄어들기는 했지만, 빈 map의 크기가 여전히 293mb로 남아있는 것을 볼 수 있다. + + - 이러한 상황이 어떻게 이루어졌는지 알기 위해서는 go에서 map의 작동방식을 알아야한다. + + - map은 모든 key 값이 고유하며 key-value 쌍의 unordered된 collection을 provides한다. + + - go 에서 map은 hash table 기반으로 만들어져 있으며, 이 data structure는 각각의 원소들이 key-value 쌍을 담고있는 bucket을 가르키는 pointer인 배열로 구성되어 있다. + + - 그림 참조 + + - key-value를 담는 bucket들은 모두 고정된 크기이며, 8개의 원소를 저장할 수 있는 배열로 되어있다. 만약 bucket 에 8개를 넘어가는 원소를 저장해야할 경우(bucket overflow), go는 또 다른 8개의 원소를 담을 수 있는 bucket을 만들고 이것을 이전 것과의 link를 한다. + + - 그림 참조 + + cf) under the hood: '실제로 어떻게 동작하고 있는가 하면' + + - go의 map은 runtime.hmap 구조체를 가리키는 pointer이다. 이 구조체는 대략 아래와 같이 생겼다. + + + ``` + type hmap struct { + B uint8 // log_2 of # of buckets + // (can hold up to loadFactor * 2^B items) + // ... + } + + ``` + + - 구조체는 B 필드를 포함하여 다양한 필드를 가지고 있다. B 필드는 map 내 buckets의 갯수를 지정한다. + + - 백만개의 원소를 추가한 후에, B 의 값은 18이 된다. 이것은 2^18 = 262,144 buckets를 의미한다. 그렇다면 모든 원소 백만 개를 제거했을 때, B의 값은 얼마가 될까? 여전히 18이다. 결론적으로 map은 여전히 동일한 갯수의 buckets를 갖고 있다. + + - 이러한 이유는 map의 bucket 갯수는 줄어들 수 없다는 성질 때문이다. 따라서 map 내에 있는 원소들을 제거한다고 해서, 존재하는 bucket의 개수에 영향을 미치지 못한다; 단지 버킷 내 슬롯에 0으로 채울 뿐이다.(; 이후 한 문장이 정확한 해석인지 몰라 원문 추가합니다. it just zeroes the slots in the buckets.) map은 오직 증가하거나 그리고 더 많은 bucket들을 가질 수 있다. 절대 줄어들지 않는다. + + - 위의 예시에서 map의 크기가 461mb에서 293mb로 내려갔음을 봤다. 원소들이 gc에 의해 수집되었기 때문에 이다. 그러나 map 자체에는 gc가 영향을 미치지 못한다. 그리고 심지어 extra buckets의 갯수(overflow로 생성된 bucket들)는 여전히 같다. + + - 다시 처음으로 돌아와 map이 cannot shrink하다는 점이 문제가 될 상황에 대해 고려해보자. 캐시를 map[int][128]btye 짜리 map을 만들어 사용한다고 가정해보자. 이 map은 customerID 당 128 bytes를 가지고 있다. 이제 1000 명의 고객을 저장하려는 상황을 고려해보자. map 크기는 여전히 constant하게 남아 있을 것이다, 그리고 우리는 map 크기가 감소될 수 없다는 사실에 대해 걱정할 필요가 없다. + + - 그러나 1시간 동안의 데이터를 저장하고 싶다고 가정해보자. 그리고 회사에서 블프에 한 시간정도 큰 행사를 하는 상황이 왔다고 가정해보자. 아마도 수백만의 고객들이 시스템에 연결될 것이다. 블프가 며칠 지난 후에, 시스템 내의 map은 블프 최다 접속자 때와 같이 동일한 수의 buckets를 가지고 있다. 이러한 상황은 왜 메모리 내에 map의 size가 큰 감소를 하지 않고, 높은 memory consumption을 경험하는지 설명해준다. + + - 서비스를 재부팅하는 것 없이 map이 소비하는 메모리 총량을 정리하기 위해서 어떤 방법이 있을까? 첫번째로는 일정한 간격으로 현재 map의 copy본을 re-create하는 것이다. 예를 들어 한 시간 간격으로, 새로운 map을 만들고, 그 map으로 모든 원소들을 복사하고 기존의 map을 방출시켜 버리는 것이다. 이 방법의 주요 단점은 새로운 map을 copy하고 다음 garbage collection까지 짧은 기간동안 현재 메모리의 두배를 사용할 수 있다는 것이다. + + - 또 다른 방법으로는 map 타입을 배열 pointer로 바꾸는 것이다. 이것은 버킷의 수에 큰 영향을 미치지는 못하지만 각각의 bucket entry들이 128bytes 짜리 value를 가지고 있는 대신 value의 size에 대한 pointer를 가지고 있을 것이다. + + ``` + map[int][128]byte ---> map[int]*[128]byte + ``` + + - 그림 참조 + + - 위 그림처럼, `map[int]*[128]byte` 타입은 모든 원소들을 제거한 후에 요구되는 메모리 크기는 상당히 적다. 또한 이 경우, peak time 동안에 필요로 되는 메모리의 크기도 상당히 작아 소비되고 있는 메모리를 줄이는데 최적화를 할 수 있다. + + - NOTE: 만약 key 혹은 value 가 128bytes 이상이라면, go 는 map 내 bucket에 직접적으로 저장하지 않는다. 대신 go 는 key나 value에 대한 참조를 가리키는 pointer를 저장한다. + + - 결론 + + - 위에서 봤던 것처럼, n개의 elements를 map에 추가하고 모든 elements를 삭제하는 것은 메모리에 같은 갯수의 bucket이 남아있다는 것을 의미한다. 따라서, 이 사실을 기억해야한다, Go map은 only grow in size하고, 메모리 consumption에서도 동일하기 때문이다. + + - 자동으로 메모리 내 map 크기를 줄이는 전략은 없다. + + - 만약 높은 메모리 소비를 유발한다면, go가 map을 re-create 하게 하거나 혹은 pointer를 사용하여 map의 크기를 최적화 시킬 수 있는지 고려해야한다. + + +[ go struct ] + + - 참조 링크입니다. + + cf) https://dev.to/deadlock/golang-writing-memory-efficient-and-cpu-optimized-go-structs-2ick + + cf) https://anandadwirahma.medium.com/save-memory-in-golang-by-compose-struct-correctly-f649d1f457dd + + - 위 링크에서는 말하는 내용은 대략 기록하였습니다. + + - go 에서 구조체의 크기는 각 필드들의 합보다 더 큰 크기를 갖고 있을 수 있다. + + - 이러한 이유는 memory allocation에 있다. + + - 구조체를 작성할 떄, 필드의 크기가 내림차순 순으로 작성하는 것이 가장 메모리를 최적화할 수 있는 방법이다. diff --git a/http/section-next/readme.md b/http/section-next/readme.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/http/section-next/readme.md @@ -0,0 +1 @@ + diff --git "a/http/section1-\354\235\270\355\204\260\353\204\267/readme.md" "b/http/section1-\354\235\270\355\204\260\353\204\267/readme.md" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/http/section1-\354\235\270\355\204\260\353\204\267/readme.md" @@ -0,0 +1 @@ + diff --git "a/http/section2-URI\354\231\200/readme.md" "b/http/section2-URI\354\231\200/readme.md" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/http/section2-URI\354\231\200/readme.md" @@ -0,0 +1 @@ + diff --git a/http/section3-HTTP/readme.md b/http/section3-HTTP/readme.md new file mode 100644 index 0000000..9a7f8af --- /dev/null +++ b/http/section3-HTTP/readme.md @@ -0,0 +1,45 @@ +[ 모든 것이 HTTP ] + +* 모든 것이 HTTP(HyperText Trasfer Protocol) + + - html 같은 hyper-text (문서 간의 링크를 연결한 것)를 전송하는 프로토콜로 시작 + + - 그러나 지금은 텍스트 뿐만 아니라 이미지, 영상, 음악, 파일, JSON&XML(서버끼리 통신할 때 전송하는 것) 등 다양한 것들, 모든 데이터의 형태를 HTTP를 통해 보낼 수 있다. + + - TCP 프로토콜을 직접 연결해서 데이터를 보내는 경우는 거의 없다, 게임 서버나 특수한 경우에는 그렇게 한다. + + - 모바일 게임 같은 경우, HTTP 프로토콜로도 개발되고 있다. + +
+ +* HTTP 역사 + + - HTTP/1.1 버젼에서 현재에서 사용되는 상당 부분이 이때 만들어짐. 가장 많이 사용하고, 우리에게 가장 중요한 버전이다. 따라서 HTTP1.1 버젼을 잘알아둬야 한다. + +* 기반 프로토콜 + + - TCP: HTTP/1.1, HTTP/2 // 이 두버젼은 TCP 프로토콜 위에서 동작한다. + + - UDP: HTTP/3 // HTTP/3버젼은 UDP 기반으로 개발이 되어 있다. + + Q. TCP가 안전하고 좋은 것 아닌가? + + A. TCP는 3 way hand-shake, 많은 양의 데이터, 속도가 빠르지 않은 매커니즘이란 특성을 갖고 있기에 이것을 UDP 프로토콜 위에 Application level에서 성능을 최적화하도록 하기 위해 설계된 것이 HTTP3 + +
+ +* HTTP 특징 + + - 클라이언트 서버 구조 // + + - 무상태 프로토콜(stateless), 비연결성 // + + - HTTP 메시지 // 통신할 떄 HTTP 메시지를 사용한다. + + - 단순함, 확장가능 // + + +* 클라이언트 서버 구조 +* Stateful, Stateless +* 비연결성(connectionless) +* HTTP 메세지 diff --git "a/http/section4-HTTP\353\251\224\354\204\234\353\223\234/readme.md" "b/http/section4-HTTP\353\251\224\354\204\234\353\223\234/readme.md" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/http/section4-HTTP\353\251\224\354\204\234\353\223\234/readme.md" @@ -0,0 +1 @@ + diff --git "a/http/section5-HTTP\353\251\224\354\204\234\353\223\234/readme.md" "b/http/section5-HTTP\353\251\224\354\204\234\353\223\234/readme.md" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/http/section5-HTTP\353\251\224\354\204\234\353\223\234/readme.md" @@ -0,0 +1 @@ + diff --git a/http/section6-HTTP/readme.md b/http/section6-HTTP/readme.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/http/section6-HTTP/readme.md @@ -0,0 +1 @@ + diff --git "a/http/section7-HTTP\355\227\244\353\215\2241-\354\235\274\353\260\230\355\227\244\353\215\224/readme.md" "b/http/section7-HTTP\355\227\244\353\215\2241-\354\235\274\353\260\230\355\227\244\353\215\224/readme.md" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/http/section7-HTTP\355\227\244\353\215\2241-\354\235\274\353\260\230\355\227\244\353\215\224/readme.md" @@ -0,0 +1 @@ + diff --git "a/http/section8-HTTP\355\227\244\353\215\2242-\354\272\220\354\213\234,\354\241\260\352\261\264\353\266\200\354\232\224\354\262\255/readme.md" "b/http/section8-HTTP\355\227\244\353\215\2242-\354\272\220\354\213\234,\354\241\260\352\261\264\353\266\200\354\232\224\354\262\255/readme.md" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/http/section8-HTTP\355\227\244\353\215\2242-\354\272\220\354\213\234,\354\241\260\352\261\264\353\266\200\354\232\224\354\262\255/readme.md" @@ -0,0 +1 @@ + diff --git "a/http/section8-HTTP\355\227\244\353\215\2242-\354\272\220\354\213\234\354\231\200/readme.md" "b/http/section8-HTTP\355\227\244\353\215\2242-\354\272\220\354\213\234\354\231\200/readme.md" new file mode 100644 index 0000000..8b13789 --- /dev/null +++ "b/http/section8-HTTP\355\227\244\353\215\2242-\354\272\220\354\213\234\354\231\200/readme.md" @@ -0,0 +1 @@ + diff --git a/js/deep-dive/22.md b/js/deep-dive/22.md new file mode 100644 index 0000000..86a1d6c --- /dev/null +++ b/js/deep-dive/22.md @@ -0,0 +1,24 @@ + ## this + + - 객체: 상태(state)를 나타내는 property와 동작(behavior)을 나타내는 메서드를 하나의 논리적인 단위로 묶은 복합적인 자료 구조 + + - 메서드가 자신이 속한 객체의 프로퍼티를 참조하려면 먼저 자신이 속한 객체를 가리키는 식별자를 참조할 수 있어야한다. + + - 객체 리터럴(아래 에재 참조) 방식으로 생성한 객체의 경우 메서드 내부에서 메서드 자신이 속한 객체를 가리키는 식별자를 재귀적으로 참조할 수 있다. + + ``` + const circle = { + radius: 5, + + getDiameter() { // 이 메서드가 자신이 속한 객체의 프로퍼티나 다른 메서드를 참조하려면 + return 2 * circle.radius; // 자신이 속한 객체인 circle을 참조할 수 있어야 한다. + } + + } + ``` + + - getDiameter 메서드 내에서 메서드 자신이 속한 객체를 가리키는 식별자 circle을 참조하고 있다. 이 참조 표현식이 평가되는 시점은 getDiameter 메서드가 호출되어 함수 몸체가 실행되는 시점이다. + + - 위 예제의 객체 리터럴은 circle 변수에 할당되기 직전에 평가된다. 따라서 getDiameter 메서드가 호출되는 시점에는 이미 객체 리터럴의 평가가 완료되어 객체가 생성되었고, circle 식별자에 생성된 객체가 할당된 이후다. 따라서 메서드 내부에서 circle 식별자를 참조할 수 있다. + + - 하지만 자기 자신이 속한 객체를 재귀적으로 참조하는 방식은 일반적이지 않으며 바람직하지도 않다. diff --git a/js/deep-dive/23.md b/js/deep-dive/23.md new file mode 100644 index 0000000..e9644d1 --- /dev/null +++ b/js/deep-dive/23.md @@ -0,0 +1,175 @@ +## 실행 컨텍스트 + + + + * 실행 컨텍스트 + + - 자바스크립트의 동작 원리를 담고 있는 핵심 개념 + + - 따라서 위 개념을 잘 이해하면 아래의 개념이 이해된다고 한다. + + - js가 스코프를 기반으로 식별자와 식별자에 바인딩된 값(식별자 바인딩)을 관리하는 방식 + + - 호이스팅이 발생하는 이유 + + - 클로저의 동작 방식 + + - 태스크 큐와 함께 동작하는 이벤트 핸들러와 비동기 처리의 동작 방식 + + (무조건 빡세게 이해하고 넘어가야 한다.) + + + * ECMAScript 사양은 소스코드(ECMAScript code)를 4가지 타입으로 구분하고, 4가지 타입의 소스 코드는 실행컨텍스트를 생성한다. + + - 전역 코드 + + -> 전역에 존재하는 소스코드 + + -> 전역에 정의된 함수, 클래스 등의 내부 코드는 포함 X + + + - 함수 코드 + + -> 함수 내부에 존재하는 소스코드 + + -> 함수 내부에 중첩된 함수, 클래스 등의 내부 코드는 포함 X + + + - eval 코드 + + -> 빌트인 전역함수인 eval 함수에 인수로 전달되어 실행되는 소스코드 + + + - 모듈 코드 + + -> 모듈 내부에 존재하는 소스코드 + + -> 모듈 내부의 함수, 클래스 등의 내부 코드는 포함 X + + + => 이렇게 소스코드(실행 가능한 코드, executable code)를 4가지 타입으로 구분하는 이유는 소스코드의 타입에 따라 실행 컨텍슬트를 생성하는 과정과 관리 내용이 다르기 때문 + + * 소스코드의 평가와 실행 + + - 모든 소스코드는 실행에 앞서 평가 과정을 거치며 코드를 실행하기 위한 준비를 한다. + + - 즉, 자바스크립트 엔진은 소스코드를 2개의 과정, "소스코드의 평가"와 "소스코드의 실행" 과정으로 나누어 처리한다. + + + * 평가 과정에서는 + + - 실행 컨텍스트를 생성하고 변수, 함수 등의 선언문만 먼저 실행하여 실행된 변수나 함수 식별자를 키로 실행 컨텍스트가 관리하는 스코프(렉시컬 환경의 환경 레코드)에 등록한다. + + * 이후 평가 과정이 끝나면 + + - 선언문을 제외한 소스코드가 순차적으로 실행되기 시작한다. 즉, 런타임이 시작된다. + + - 이때 소스코드 실행에 필요한 정보, 즉 변수나 함수의 참조를 실행 컨텍스트가 관리하는 스코프에서 검색해서 취득한다. + + - 그리고 변수 값의 변경 등 소스코드의 실행 결과는 다시 실행 컨텍스트가 관리하는 스코프에 등록된다. + + + * 실행 컨텍스트의 역할 + + ``` + // 전역 변수 선언 + const x = 1; + const y = 2; + + // 함수 정의 + function foo(a) { + // 지역 변수 선언 + const x = 10; + const y = 20; + + // 메서드 호출 + console.log(a+x+y); + } + + // 함수 호출 + foo(100); + + // 메서드 호출 + console.log(x + y); + ``` + + - 위와 같은 코드를 자바스크립트 엔진은 아래와 같은 방식으로 평가하고 실행한다. + + 1-1. 전역 코드 평가 + + - 전역 코드 평가 과정을 거치며 전역 코드를 실행하기 위한 준비를 한다. + + - 소스코드 평가 과정에서는 선언문만 먼저 실행한다. + + - 따라서 전역 콛의 변수 선언문과 함수 선언문이 먼저 실행되고, 생성된 전역 변수와 전역 함수는 실행 컨텍스트가 관리하는 전역 스코프에 등록된다. + + - var로 선언된 전역 변수와 함수 선언문으로 정의된 전역 함수는 전역 객체의 '프로퍼티'와 '메서드'가 된다. + + + 1-2. 전역 코드 실행 + + - 전역 코드 평가 과정이 끝나면 런타임이 시작되어 전역 코드가 순차적으로 실행되기 시작한다. + + - 이때 전역 변수에 값이 할당되고 함수가 호출된다. + + - 함수가 호출되면 순차적으로 실행되던 전역 코드의 실행을 일시 중단하고 코드 실행 순서를 변경하여 함수 내부로 진입한다.(함수가 끝나고 복귀할 주소(return address)를 스택에서 관리한다. 시스템 해킹할 때, 복귀 주소가 중요하게 사용된다고 한다. cf) https://g-idler.tistory.com/13) + + + 2-1. 함수 코드 평가 + + - 함수 호출에 의해 코드 실행 순서가 변경되어 함수 내부로 진입하면 함수 내부의 문들을 실행하기에 앞서 함수 코드 평가 과정을 거치고 함수 코드를 실행하기 위한 준비를 한다. + + - 이때, 매개변수와 지역 변수 선언문이 먼저 실행되어 생성된 매개변수와 지역변수는 실행 컨텍스트가 관리하는 지역 스코프에 등록된다. + + - 또한 함수 내부에서 지역 변수처럼 사용할 수 있는 arguments 객체가 생성되어 지역 스코프에 등록되고 this 바인딩도 결정된다. + + + 2-2. 함수 코드 실행 + + - 함수 코드 평가 과정이 끝나면 런타임이 시작되어 함수코드가 순차적으로 실행된다. + + - 이때 매개변수와 지역변수에 값이 할당되고 console.log 메서드가 호출된다. + + - console.log 메서드를 호출하기 위해 먼저 식별자인 console을 스코프 체인을 통해 검색한다. + + - 이를 위해 함수 코드의 지역 스코프는 상위 스코프인 전역 스코프와 연결되어야 한다. + + - 하지만 console 식별자는 스코프 체인에 등록되어 있지 않고 전역 객체에 프로퍼티로 존재한다. + + - 이는 전역 객체의 프로퍼티가 마치 전역 변수처럼 전역 스코프를 통해 검색 가능해야 한다는 것을 의미 + + + - 다음은 log 프로퍼티를 console 객체의 프로토타입 체인을 통해 검색한다. + + - 그후, console.log 메서드에 인수로 전달된 표현식 a + x + y가 평가된다. + + - a, x, y 식별자는 스코프 체인을 통해 검색한다. + + - console.log 메서드의 실행이 종료되면 함수 코드 실행 과정이 종료되고 함수 호출 이전으로 되돌아가 전역 코드 실행을 계속한다.(return address를 스택에 넣어논다.) + + - 이처럼 코드가 실행되려면 스코프를 구분하여 식별자와 바인딩된 값이 관리되어야 한다. + + - 그리고 중첩 관계에 의해 스코프 체인을 형성하여 식별자를 검색할 수 있어야 하고, 전역 객체의 프로퍼티도 전역 변수처럼 검색할 수 있어야 한다. + + + - 또한 함수 호출이 종료되면 함수 호출 이전으로 되돌아가기 위해 현재 실행 중인 코드와 이전에 실행하던 코드를 구분하여 관리해야 한다. + + - 이처럼 코드가 실행되려면 다음과 같이 스코프, 식별자, 코드 실행 순서 등의 관리가 필요하다. + + 1. 선언에 의해 생성된 모든 식별자(변수, 함수, 클래스 등)를 스코프를 구분하여 등록하고 상태 변화(식별자에 바인딩된 값의 변화)를 지속적으로 관리할 수 있어야 한다. + + 2. 스코프는 중첩 관계에 의해 스코프 체인을 형성해야 한다. 즉, 스코프 체인을 통해 상위 스코프를 이동하며 식별자를 검색할 수 있어야 한다. + + 3. 현재 실행 중인 코드의 실행 순서를 변경(예를 들어, 함수 호출에 의한 실행 순서 변경)할 수 있어야 하며 다시 되돌아갈 수도 있어야 한다. + + + => 이 모든 것을 관리하는 것이 바로 "실행 컨텍스트"다. 실행 컨텍스트는 소스코드를 실행하는 데 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역이다. + + => 실행 컨텍스트는 식별자(변수, 함수, 클래스 등의 이름)를 등록하고 관리하는 스코프와 코드 실행 순서 관리를 구현한 내부 매커니즘으로, 모든 코드는 실행 컨텍스트를 통해 실행되고 관리한다. 식별자와 스코프는 실행 컨텍스트의 렉시컬 환경으로 관리하고 코드 실행 순서는 실행 컨텍스트 스택으로 관리한다. + + + + + + + diff --git a/js/notepad.md b/js/notepad.md deleted file mode 100644 index b449341..0000000 --- a/js/notepad.md +++ /dev/null @@ -1,34 +0,0 @@ -* for문 없이 배열 생성하기 - - - 5개 짝수 배열 만들기 - - `1. Array(5).fill(0).map((el, idx) => i+2);` - - `2. Array.from({ length: 5}, (v, i) => i); // v는 각 원소(undefined), i는 인덱스` - -
- 이하 부터는 stackoverflow 지식인들이 배열 만드는 방법... - - `1. Array.from(Array(5).keys()) // [0, 1, 2, 3, 4]` - - `2. [...Array(5).keys()] // [0, 1, 2, 3, 4]` - - `3. let N = 5; Array.apply(null, {length: N}).map(Number.call, Number)` - - `4. (N개의 무작위 배열 만드는 방법) - let N = 5; Array.apply(null, {length: N}).map(Function.call, Math.random); - // [0.7082694901619107, 0.9572225909214467, 0.8586748542729765, 0.8653848143294454, 0.008339877473190427]` - -
- 2번까지는 이해가 됬는데, 3번 부터는 설명을 적어놓아야 할 것 같다..(for문 안써서 배열 만드는게 뭔가 멋져 보이고 효율적이라는 생각을 했는데,, 아래 설명을 적으면서 괜히 복잡하게 배열을 만드는 건 아닌지, 그래서 더 효율이 떨어지는 건 아닌지 고민하게 됬다.. 까불지 말고 그냥 for문으로 배열 만드는 것도 괜찮을 것 같다) - - Number.call(undefined, N)은 Number(N)과 동일하다고 한다. Number(N)은 N을return 해준다. - - 그리고 Array.apply(null, [undefined, undefined])는 Array(undefined, undefined)와 동일하다고 한다. Array(undefined, undefined)는 2개의 원소가 각각 undefined인 배열이다. - - 이 다음 설명은.. 오늘은 도저히 안될 것 같고, 내일 21년 이브날에 기필코 작성해야겠다.. - - cf) https://stackoverflow.com/questions/3746725/how-to-create-an-array-containing-1-n - - cf) https://stackoverflow.com/questions/50478967/what-is-array-mapfunction-call-number - diff --git a/js/readme.md b/js/readme.md new file mode 100644 index 0000000..69a168d --- /dev/null +++ b/js/readme.md @@ -0,0 +1,517 @@ +* 읽어야 할 책 목록 + + gpt가 추천해준 도서 + + - "JavaScript: The Good Parts" by Douglas Crockford +이 책은 자바스크립트 언어의 핵심 개념과 사용법에 초점을 맞춘 베스트셀러입니다. 자바스크립트의 장단점을 잘 설명하고, 좋은 부분에 집중하여 핵심 개념을 익힐 수 있도록 도와줍니다. + + - "Eloquent JavaScript" by Marijn Haverbeke +이 책은 자바스크립트 프로그래밍 언어를 학습하기 위한 훌륭한 자료입니다. 초보자부터 중급자까지 다양한 수준의 내용을 다루고 있으며, 실제 예제와 연습문제를 통해 실력을 향상시킬 수 있도록 구성되어 있습니다. + + - "CSS Secrets" by Lea Verou +이 책은 CSS의 고급 기술과 비법을 알려주는 책입니다. 다양한 CSS 속성과 트릭, 기술적인 해결책을 소개하며, 웹 디자인과 프론트엔드 개발에서 더 나은 결과를 얻을 수 있는 방법을 알려줍니다. + + - "React Up and Running" by Stoyan Stefanov +이 책은 React를 사용하여 현대적인 웹 애플리케이션을 개발하는 방법을 알려줍니다. React의 기본 개념부터 실전 프로젝트까지 다루며, 효율적인 컴포넌트 구성과 상태 관리, 라우팅 등을 배울 수 있습니다. + + - "The Pragmatic Programmer" by Andrew Hunt and David Thomas +이 책은 프로그래머로서의 실력 향상을 위한 가이드로서, 프로그래밍 원리와 실무적인 조언을 제공합니다. 코드 작성, 디버깅, 테스팅, 리팩토링, 커뮤니케이션 등 개발자로서 필요한 다양한 측면을 다루고 있습니다. + + - "Learning Web Design" by Jennifer Niederst Robbins +이 책은 웹 디자인과 프론트엔드 개발에 초점을 맞춘 입문서입니다. HTML, CSS, 그리고 웹 디자인 기초에 대해 상세히 설명하며, 실제 예제와 튜토리얼을 통해 실력을 키울 수 있도록 구성되어 있습니다. + + - "JavaScript: The Definitive Guide" by David Flanagan +이 책은 자바스크립트 언어의 전체적인 내용을 상세히 다루고 있으며, ES6 이후의 최신 기능까지 포함하고 있습니다. 자바스크립트의 핵심 문법과 개념, 객체 지향 프로그래밍, DOM 조작, 비동기 프로그래밍 등을 포괄적으로 다루고 있습니다. + + - "CSS: The Definitive Guide" by Eric A. Meyer and Estelle Weyl +이 책은 CSS의 깊이 있는 내용을 다루고 있으며, CSS의 다양한 기능과 속성, 레이아웃, 반응형 웹 디자인 등을 상세하게 설명합니다. 웹 개발자로서 CSS에 대한 심도 있는 이해를 갖추기 위한 필수 참고서입니다. + + - "Vue.js: Up and Running" by Callum Macrae +이 책은 Vue.js 프레임워크에 초점을 맞춘 입문서입니다. Vue.js의 기본 개념과 사용법을 알기 쉽게 설명하며, 실전 프로젝트를 통해 Vue.js를 활용한 웹 애플리케이션 개발 방법을 익힐 수 있습니다. + + - "The Design of Everyday Things" by Don Norman +이 책은 사용자 인터페이스와 상호작용 설계에 대한 기본 원칙과 이론을 다루는 UX 디자인의 고전적인 책입니다. 사용자 중심의 설계에 대한 통찰력을 제공하며, 웹 애플리케이션 개발에서 사용자 경험을 개선하는 데 도움이 됩니다. + + + +* 쉬프트 엔터 감지 + + - https://stackoverflow.com/questions/3044083/what-is-the-key-code-for-shifttab + + - event의 shift키를 감지하는 e.shiftKey(boolean 값) && e.keyCode 값을 비교하면 된다. + +* for in / for of 차이 + + image + + +* js 메모리 누수 + + cf) https://ui.toast.com/posts/ko_20210611 글을 정리한 내용입니다. + + - 웹 패이지가 멈추는 경우, 원인이 무엇일까 라는 질문을 받으면 어떠한 답변을 할 수 있을까 + + - 네트워크 요청이 너무 많아 데이터 전송 속도가 느려지는 지 확인한다. 이는 캐싱으로 처리하여 해결 가능하다. + + - 특정 리소스의 번들이 너무 클 수 있기에, 해당 번들을 분할하여 해결한다. + + - 많은 루프를 돌면서 메인 스레드를 오래 점유하고 있지는 않은지 자바스크립트 코드를 검토한다. + + - 브라우저가 특정 프레임에 너무 많은 것을 렌더링한 문제일 수 있다. + + - 페이지 렌더링 프로세스 중에서 너무 많은 리페인트와 리플로우가 일어난다. + + - 메모리 누수로 인해 페이지 로딩 속도에 문제의 원인이 된다. + + #### 스택 메모리와 힙 메모리 + + - 자바스크립트 메모리는 단순 변수에 사용되는 스택 메모리와 복잡한 객체에 사용되는 힙 메모리로 구분된다. + + - 단순 변수들은 원시타입이라고 불리며 String, Number, Boolean, Null, Undefined, Symbol, Bigint 등이 있다.
복잡한 객체는 참조 데이터 타입이라고 하며, Object, Array, Function 등이 있다. + + #### 자바스크립트의 가비지 컬렉션 + + - 가비지 컬렉션은 가비지 데이터를 수집하는데, 작동 매커니즘은 수동과 자동 두가지 방식으로 나뉜다. + + - c와 c++은 수동 정리 매커니즘을 사용한다. 개발자가 직접 메모리를 할당하고 필요가 없어지면 해당 메모리를 비워줘야 한다. 반면 자바스크립트는 자동 정리 매커니즘을 사용한다. 모든 것을 자동으로 처리하기에 얼마나 많은 메모리를 할당하고 비우는지 신경 쓸 필요가 없다.
하지만 그렇다고 메모리 관리에 신경을 쓸 필요가 없는 것은 아니다. + + - 일반적으로 전역 변수는 자동으로 정리되지 않는다. + + + +* generator (제네레이터) + + - 함수의 흐름을 중간 제어할 수 있다. 함수의 흐름을 멈추게 할 수 있다. + + ``` + const gen = function* () {} + + gen() // gen {} + + gen().next() // {value: undefined, done: true} + + cons gen1 = function* () { + console.log(1); + yield; + console.log(2); + yield 4; + } + + const generator = gen1(); + + generator.next(); // 1 {value: undefined; done: false;}출력하고 멈춤. + generator.next(); // 2 {value: 4; done: false;} 출력하고 멈춤. + generator.next(); // {value: undefined; done: true;} 출력하고 멈춤. + + ``` + +* 메시징 시스템 + + - 분산형 아키텍처에서의 메시징 시스템이란 용어는 네트워크를 통한 정보 교환을 용이하게 하기 위한 솔루션, 패턴 및 일련의 아키텍처를 의미. + + - 메시지는 목적의 따라 3가지 유형의 메시로 구분. (명령 메시지, 이벤트 메시지, 도규먼트 메시지) + + - 명령 메시지 + + - 수신 측에서 어떤 동작이나 작업을 수행하도록 하는 것 + + - 원격 프로시저 호출(RPC) 시스템, 분산된 연산 수행, 데이터를 요청하데 사용 + + - RESTful HTTP 호출이 이 명령의 예시. + + - 이벤트 메시지 + + - 다른 컴포넌트에 무엇인가가 발생했음을 알리는데 사용 + + - 일반적으로 이벤트의 유형을 포함, 때로는 컨텍스트, 주제 같은 세부적인 정보도 포함 + + - 브라우저에서 롱폴링(long polling)이나 WebSocket을 통하여 데이터가 변경되거나 일반적인 시스템의 상태가 변화되었을 때 서버로부터 알림을 받기 위해 이벤트 메시지를 사용 + + - 이벤트의 사용은 시스템의 모든 노드를 동일한 페이지에서 유지할 수 있도록 하기에 매우 중요하다. + + - 도큐먼트 메시지 + + - 컴포넌트와 시스템 간의 데이터 전송을 의미 + + - 도큐멘트 메시지와 명령 메시지와 구별되는 주요 특징은 수신자에게 데이터를 어떻게 처리할지 알려주는 정보가 메시지에 포함되어 있지 않다는 것이다. + + - 이벤트 메시지와의 주요한 차이는 주로 발생한 특정한 사건과 연관성이 없다는 것이다. + + - 비동기 통신 + + - 동기 통신에 비해 더 적은 리소스를 사용하고 더 나은 병렬처리를 수행할 수 있다. + + - 메시지를 저장한 이후, 즉시 혹은 일정한 시간 지연 후에 전달할 수 있다. + + - 메시징 시스템에서는 메시지 큐란 컴포넌트를 통하여 메시지를 송신자와 수신자 간의 통신을 중재하고 메시지가 대상에 전달되기 전에 메시지를 저장한다. + + - 메세지 전달 방식(Peer-to-peer / Broker) + + - P2P 방식 + + - 수신자에게 직접 p2p 방식으로 전달되는 것. + + - 모든 노드는 메시지를 수신자에게 직접적으로 전달하기에 노드가 수신자의 주소와 포트를 알아야하고 프로토콜과 메시지 형식을 이해하고 있어야 한다. 브로커는 이러한 복잡함으로부터 자유롭다. + + - 브로커 방식 + + - 중앙 중계 시스템을 통해 수신자에게 전달되는 방식. + + - 각 노드는 완전히 독립적이며, 다른 노드에 대한 세부 정보를 직접 알지 못하더라도 수 많은 피어들과 통신할 수 있다. + + - 브로커는 다른 통신 프로토콜 간의 브리지 역할을 할 수도 있다. (ex, RabbitMQ 브로커, AMQP, MQTT, STOMP를 지원하여 여러 어플리케이션에서 서로 다른 프로토콜로 통신이 가능하도록 한다.) + +
+ +* 고차함수 + + ``` + const onClick = () => () => { + ... + } + + 위 코드는 아래의 코드와 동일하다 + + const onClick = () => ()=> { + return () => { + ... + }; + } + ``` + + - 고차함수를 사용할때 event를 어디다가 넣어야 할 지(1번 혹은 2번??) 고민일때 함수의 return 값으로 대치해서 생각하면 편하다. + + ``` + const onClick = (1) => (2) => { + console.log(e.target); + } + + document.querySelector("#header").addEventListener('click', onClick()) + + ``` + + -> onClick의 return 값으로 대체해볼것, 만약 1번 자리에 event 객체가 있었다면, 아래 코드와 같아진다. + + ``` + document.querySelector("#header").addEventListener('click', () => { + console.log(e.target); + }) + + event 객체가 없는데, event 객체에 접근하는 오류가 생긴다. 만약 2번 자리에 event 객체가 있었다면, 아래 코드와 같아지고 이게 맞는 코드이다. + + document.querySelector("#header").addEventListener('click', (e) => { + console.log(e.target); + }) + + ``` + +
+ +* encodeURI() + + - 인터넷 주소에서 사용하는 :(semi-colon), ;(colon), /(slash), =, ?, & 등을 제외하고 인코딩하는 함수이다. + + - encodeURIComponent() : 모든 문자를 인코딩하는 함수이다. + + ex)'hello?yo u'라는 글자를 encodeURI(), encodeURIComponent() 했을 때의 차이가 있다. 첫번째는 hello?yo%20u 두번째는 hello%3Fyo%20u와 같은 결과가 출력된다. + +
+ +* Object.Entries() + + - return 값: 지정된 객체 자체의 열거 가능한 문자 속성 [key, value] 쌍의 배열 + + ``` + const rspCoord = { + 바위: '0', + 가위: '-142px', + 보: '-284px', + } + + const RSP = () => { + const [imgCoord, setImgCoord] = useState(rspCoord.바위); + + const computerChoice = (imgCoord) => { + return Object.entries(rspCoord).find((v) => { + return v[1] === imgCoord + })[0]; + } + + ... + + computerChoice(imgCoord); + + } + + ``` + + +* Event Bubbling + + - html 특성 상, 자식 요소에서 발생한 event는 부모에서도 발생하게 된다 + + 가령, 아래와 같은 코드 구조가 있고, td에서 발생하는 event가 있을 경우, tr에서도 event가 발생하고, table에서도 발생하게 되고, body에서도 발생하게 된다. 이 현상이 event bubbling 이라고 한다. 이 bubbling이 있어야 하는 이유는 td 태그 내에 span 태그가 있다고 가정하고 이때 td를 클릭한 경우 이벤트를 발생시키게 해놓았는데, span 태그를 클릭하여 td에 걸어놓은 event 발생이 안되는 문제를 위해 존재한다고 한다. + + - event capturing: 부모에서 발생한 event가 자식에게 까지 내려오는 현상. 보통 event capturing은 팝업 닫기를 구현할 때 쓴다고 한다. 팝업의 바깥 쪽 영역을 클릭하여 팝업창이 닫히게끔 하는 용도로 사용된다. 팝업의 바깥쪽 영역은 팝업의 부모이고 이 부모에서 발생한 이벤트를 팝업창으로 전달하여 팝업창을 꺼지게끔 하면 된다고 한다. + + ``` + + + + + +
+ + ``` + + +
+* Event Deligation + + ``` + + + + + + + + + + + ``` + + +이벤트를 걸어줄 때, 요소 하나 하나마다 addEventListener를 통해 걸게 되면, 성능이 안좋게 된다. + +따라서 event를 걸어줄 요소들의 부모에 event를 걸어주면, 성능을 향상 시킬 수 있다. 즉, event를 걸어줄 요소들의 부모로 event 처리를 위임하는 것이다. + +위에 코드에서는 각 button 들에 addEventListener를 등록하는 것이 아니라 menu라는 클래스를 갖는 부모 div element에 event를 등록하는 것이다. + +하지만 이러한 경우, 아래의 상황을 처리해야한다. +부모에 이벤트를 걸어줬기 때문에, 그 부모 내에서 어떤 자식요소(어떤 버튼)를 클릭했는지를 구분할 수 있는 작업이 필요하다. 구분할 수 있는 방법으로는 event 객체의 target 속성을 확인하면 된다. 참고로 event 객체의 currentTarget 속성은 event가 걸려있는 요소를 출력하게 된다, eventHandler 안에서는 currentTarget과 this는 동일한 것을 나타내게 되어 있다. addEventListener를 호출하도록 한 객체를 출력한다. 곧, addEventListener가 걸려있는 객체를 출력한다. + +event.target을 통해 자식들을 구분할 수 있었지만, 자식 내에 가령 span 태그나 img 태그 같은 요소들이 있을 때, 그 요소를 클릭하면 어떤 자식인지를 구분해주는 것이 아니라, 자식 내에 span 태그 와 같은 내부에 있는 요소를 출력하게 된다. + +위 코드와 같은 경우, 어떤 버튼인지를 구분할 수 있어야 하는데, 어떤 버튼인지를 구별하는 것이 아닌 버튼 내에 자식 요소를 가르키게 된다.(출력하게 된다.) + + + +그래서 위와 같은 문제를 해결하는 방법으로는 2가지 방법(css, script)이 있다. + + + +첫번째 css를 사용하는 경우, pointer-events: none 속성을 적용시킨다. 어떤 버튼인지를 구별하기 위해 버튼 내에 있는 자식 요소들에게 pointer-events: none을 적용시킨다. 위 코드의 경우 button 하위에 있는 span, img 태그에 해당 속성을 적용시키면 된다. + +둘째, script를 사용할 경우, 아래와 같은 코드를 추가하여 진행하면 된다. + + + + +cf) 위 코드에서 element에 custom tag로 data-value를 넣어줬다. 'data-'로 시작하는 커스텀 태그를 넣어줬을 경우, 해당 element의 dataset 속성에 value라는 값이 저장된다. 따라서 e.target.dataset.value로 접근하면 각 버튼의 data-value 값을 접근할 수 있다. + + + +이렇게 css와 script로 문제를 처리할 수 있을 경우, 보통 css로 깔끔하게 처리하면 되지만, css로 처리할 경우, pointer-events: none 속성을 적용한 하위 내 모든 자식영역에서는 clickEvent가 발생하지 않는 점을 유의해야 한다고 한다. + + + +script로 처리할 경우, 좋은 점으로는 동적으로 element가 생성되는 상황에 이벤트 리스너를 따로 추가적으로 구현하지 않아도 된다는 점이다. + +* console.log와 console.dir + + [console.log] + + - 요소를 HTML과 같은 트리 구조로 출력 + + - DOM 요소에 대해 특별한 처리를 제공 + + [console.dir] + + - 요소를 JSON과 같은 트리 구조로 출력 + + - Dom 요소에 대한 특별한 처리를 제공하지 않는다. + +
+* JSON(JavaScript Object Notation) + + - 데이터를 표시하는 포맷 + + - 자바스크립트로부터 파생되어 js 구문의 형식을 따르지만, 독립적인 데이터형 포맷이다, 따라서 c, c++, java, python 등 다양한 pl에서 활용가능 + + - key: value 형식으로 포맷이 정해져 있으며, 주로 비동기 브라우저/서버통신을 위해 사용된다. + + - JSON.parse(): JSON 포맷으로 되어 있는 문자열을 JSON 객체로 변환시킨다. JSON.parse(문자열) + + cf) JSON.parse() return 값은 Object / 이로 인해 JSON.parse()의 결과는 늘 객체형태라고 생각했는데, JSON.parse(JSON.stringify([a, b, c]))의 결과값은 [a, b, c], 배열이다. + + - JSON.stringify(): 인수로 전달받은 자바스크립트 객체를 문자열로 변환하여 반환. + + - JSON.toJSON(): js의 Date 객체의 데이터를 JSON 형식의 문자열로 변환하여 반환. 따라서 Date.prototype 객체에서만 이 메서드를 사용할 수 있다. + + + +* Array.prototype.slice() + + - slice() 메서드는 어떤 배열의 begin부터 end까지(end 미포함)에 대한 얕은 복사본을 새로운 배열 객체로 반환합니다. 원본 배열은 바뀌지 않습니다. + + ``` + ex) + let a = ['aa', 'bb']; + let b = a.slice(); + + console.log(b); // ['aa', 'bb'] + + b[0] = 'xx'; + console.log(b); // ['xx', 'bb'] + console.log(a); // ['aa', 'bb'] + ``` + + - begin(첫 인자) + + - slice의 첫시작으로(begin) 음수가 들어왔을 경우, 배열의 끝에서부터의 길이를 나타낸다. + + - begin이 배열의 길이보다 큰 경우, 빈 배열을 return + + - begin이 undefined인 경우, 0번 인덱스부터 slice + + ``` + sthArray.slice(-2); // 배열에서 마지막 두개의 element 추출 + ``` + + - end(두번째 인자) + + - 음수 인덱스는 배열의 끝에서부터의 길이를 나타낸다. 예를 들어 slice(2, -1)는 세번째(=2번 인덱스)부터 끝에서 두번째 요소까지 추출한다. + + - end가 생략되면 slice()는 배열의 끝까지(arr.length) 추출한다. + + - end 값이 배열의 길이보다 크면, slice()는 배열의 끝까지 추출한다. + +* 일급 함수란 ? + + - 함수를 다른 변수와 동일하게 다루는 언어는 일급 함수를 가졌다고 말한다. + + - 함수를 값으로 담을 수 있어 변수에 함수를 값으로 넣기도 한다. + + - 함수의 전달인자로 함수를 전달할 수 있다. + + ``` + const temp = function() { + console.log("it's temp"); + } + + temp(); // 변수를 사용한 호출, 'it's temp' 출력 + + const hello = function() { + return function() { + console.log("HELLO") + } + } + + hello()(); // "HELLO" 출력 + + function add(a) { + return function(b) { + return a + b; + } + } + + let sum10 = add(10); + sum10(20); // 30 출력 + ``` + + +* 순수 함수란 ? + + - 순수함수의 조건 + + 1. 함수의 전달인자로 동일한 인자가 들어갈 때마다 동일한 결과값이 나와야 한다. (= 같은 입력을 받은 경우, 같은 출력을 반환) + 2. side-effect(부수적인 효과)가 발생해서는 안된다. + 3. return 값을 통해서만 소통한다. + 4. 평가 시점이 중요하지 않다. 순수함수가 아닌 경우에 동일 인자를 넣어도 다른 결과값이 나오는 상황에서 어떤 시점에 함수를 평가할지는 중요하지만 순수함수의 경우는 동일 인자가 입력되면 언제나 동일 결과가 출력되기에 평가시점을 따질 필요가 없다. + + ``` + //순수함수 + function add(a, b) { + return (a + b); + } + + //순수함수 X + let c = 10; + function sum(a, b) { + return (a + b + c); + } + + console.log(10, 20); // 40 출력 + + c = 5; + console.log(10, 20); // 35 출력 + + -> 동일 인자이지만, 결과값이 다르다 + + 부수적인 효과: 함수에서 디스크에 값을 저장하거나 외부 변수의 값을 변경하는 경우를 뜻한다. + ``` + + +* for문 없이 배열 생성하기 + + - 5개 짝수 배열 만들기 + + `1. Array(5).fill(0).map((el, idx) => i+2);` + + `2. Array.from({ length: 5}, (v, i) => i); // v는 각 원소(undefined), i는 인덱스` + +
+ 이하 부터는 stackoverflow 지식인들이 배열 만드는 방법... + + `1. Array.from(Array(5).keys()) // [0, 1, 2, 3, 4]` + + `2. [...Array(5).keys()] // [0, 1, 2, 3, 4]` + + `3. let N = 5; Array.apply(null, {length: N}).map(Number.call, Number)` + + `4. (N개의 무작위 배열 만드는 방법) + let N = 5; Array.apply(null, {length: N}).map(Function.call, Math.random); + // [0.7082694901619107, 0.9572225909214467, 0.8586748542729765, 0.8653848143294454, 0.008339877473190427]` + +
+ 2번까지는 이해가 됬는데, 3번 부터는 설명을 적어놓아야 할 것 같다..(for문 안써서 배열 만드는게 뭔가 멋져 보이고 효율적이라는 생각을 했는데,, 아래 설명을 적으면서 괜히 복잡하게 배열을 만드는 건 아닌지, 그래서 더 효율이 떨어지는 건 아닌지 고민하게 됬다.. 까불지 말고 그냥 for문으로 배열 만드는 것도 괜찮을 것 같다) + + Number.call(undefined, N)은 Number(N)과 동일하다고 한다. Number(N)은 N을return 해준다. + + 그리고 Array.apply(null, [undefined, undefined])는 Array(undefined, undefined)와 동일하다고 한다. Array(undefined, undefined)는 2개의 원소가 각각 undefined인 배열이다. + + 이 다음 설명은.. 오늘은 도저히 안될 것 같고, 내일 21년 이브날에 기필코 작성해야겠다.. + + cf) https://stackoverflow.com/questions/3746725/how-to-create-an-array-containing-1-n + + cf) https://stackoverflow.com/questions/50478967/what-is-array-mapfunction-call-number + diff --git a/js/touch-event.md b/js/touch-event.md new file mode 100644 index 0000000..c11e933 --- /dev/null +++ b/js/touch-event.md @@ -0,0 +1,22 @@ +* 모바일 환경에서 손으로 슬라이드 + + 모바일에서 메뉴를 슬라이드를 할 수 있도록 만들기 위해 작업되어 있는 코드를 분석하며 알아봐야 할 개념들을 서칭해 보았다.(참.. 슬라이드 메뉴 그동안 편하게 쓰고 있었구나 싶다.) + + * 검색 사이트: + + 슬라이드 관련(js event 객체의 changedTouches를 keyword로 검색) + + 1. https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/changedTouches + + 2. https://www.bsidesoft.com/285 + + 3. https://d2.naver.com/helloworld/80243 + +
+ 화면 내 기준되는 위치 + + 1. https://ko.javascript.info/coordinates + + +
+ 해당 사이트를 서칭하며 배운 것들을 정리해야 겠다. 그리고 어떻게 슬라이드 메뉴를 구현할 수 있는지 또한 정리해놓아야 겠다. diff --git a/middleware/readme.md b/middleware/readme.md new file mode 100644 index 0000000..4f6bff1 --- /dev/null +++ b/middleware/readme.md @@ -0,0 +1,11 @@ +* Message Queue(MQ) + + - 서비스와 서비스 사이에서 middleware 역할을 해주는 종류 + + - rabbitMQ, kafka 등이 있다 + + - 메시지 큐는 프로세스 또는 프로그램 인스턴스가 데이터를 서로 교환할 때 사용하는 통신방법 이다. + + - 더 큰 개념으로는 메시지 지향 미들웨어(Meesage Oriented Middleware: MOM)를 구현한 시스템을 의미한다. + + - 로드밸런싱의 기능 diff --git a/ngrok/how-to-use.md b/ngrok/how-to-use.md new file mode 100644 index 0000000..553bf07 --- /dev/null +++ b/ngrok/how-to-use.md @@ -0,0 +1,14 @@ +* Ngrok 사용 방법 + + 1. 설치 + + 설치 사이트(https://ngrok.com/)로 이동하여 window에 해당하는 파일을 다운받아 해당 파일 내에 실행파일인 ngrok.exe 파일을 실행한다. + + 2. 사용 방법 + ngrok.exe 파일을 실행하면 cmd 창이 나오는데, 그 cmd 창에서 보여주는 경로는 ngrok.exe 실행 파일이 있는 폴더이다. + + 그 폴더에서 ngrok http 포트번호를 type하면 해당 포트 번호에서 로컬로 작동 중인 서버를 다른 곳(외부)에서 접근 가능하다. + + * 주의 * + + 2번에 적혀 있는 명령어를 실행할 때, 한가지 사항을 더 해야하는데, 바로 실행된 ngrok 터미널 창에서 accessToken을 설정하는 것이다. diff --git a/npm-library/library.md b/npm-library/library.md index 051472a..c5ba9b8 100644 --- a/npm-library/library.md +++ b/npm-library/library.md @@ -1,10 +1,30 @@ -** project 내에서 파일 import 시 복잡한 경로를 심플하게 할 수 있도록 돕는 라이브러리 +* gts(Google Typescript Style) + + - Google에서 만든 타입스크립트 스타일 가이드로서 포맷터(formatter), 린터(linter), 자동 코드 수정(automatic code fixer)의 구성을 도와준다. + + - \`npx gts init 명령어로 시작 + +
+ +* husky + + - Node.js 개발환경에서 Git hook을 사용하기 편리하게 만들어주는 도구 + + - Git hook은 git에서의 커밋, 풀, 머지 등과 같은 이벤트에서 특정 스크립트를 실행하는 것이며, pre-commit은 커밋 직전에 실행되는 hook이다. + + - Git에서는 hook을 지원하는데, 프로그래밍에서 hook이란 특정 이벤트 또는 함수가 호출되기 전, 후에 호출이 되는 코드를 말한다. + +
+ +* project 내에서 파일 import 시 복잡한 경로를 심플하게 할 수 있도록 돕는 라이브러리 cf) https://www.npmjs.com/package/babel-plugin-module-resolver - babel-plugin-module-resolver -** 브라우저 접근 시 모바일 및 태블릿 환경인지 확인하기 위한 라이브러리 +
+ +* 브라우저 접근 시 모바일 및 태블릿 환경인지 확인하기 위한 라이브러리 - mobile-detect diff --git a/npm-library/readme.md b/npm-library/readme.md new file mode 100644 index 0000000..5a6791e --- /dev/null +++ b/npm-library/readme.md @@ -0,0 +1,13 @@ +* codemod 라이브러리 + + - 위 라이브러리를 활용하여 특정 라이브러리가 버젼 변경되었을 때, code를 손쉽게 변경할 수 있다. + + - codemod가 좋은 점이, react-router5에서 react-router6로 업데이트할 때 변경해야될 부분을 다른 사람들이 만들어 놓은게 있다, 이걸 활용하면 쉽게 바꿀 수 있다. + +
+ +* version 업그레이드된 라이브러리에서 변경된 내용확인할 때 + + - ' library + github '으로 검색할 것 + + - github에서 CHANGE LOG, migration guide, release 내용을 확인해보면 좋다. diff --git a/npm/readme.md b/npm/readme.md new file mode 100644 index 0000000..5aaa972 --- /dev/null +++ b/npm/readme.md @@ -0,0 +1,20 @@ +* peerDependencies + + - 일반적으로 dependency는 내가 만든 모듈에서 사용하는 패키지들을 지정하는 반면, peerDependencies는 반대로 내가 만든 모듈이 다른 모듈과 함께 동작할 수 있다는 호환성을 표시하는 것 + + - 자신이 만든 모듈이 라이브러리의 모든 버젼이 아닌 특정 버젼에서만 동작하게 되는 경우, 이러한 정보를 표시해야하는데 이 때, 사용하는 것이 peerDependencies 이다. + + +* optinalDependencies + + - 사용을 원하는 모듈이지만, 없거나 설치가 실패해도 npm의 패키지 설치 과정이 중단되지 않도록 하려면, optinalDependencies를 사용한다. + + - 이때 버전을 포함한 패키지 이름 혹은 url dependencies와 같은 방식으로 기재한다. + + - 의존성 모듈이 없는 경우를 대비한 개발을 할 때 사용하는 것이 좋다. + + ex) 모듈이 없는 경우, 특정 로직을 작동시킬 수 있도록 처리하는 것이 좋다. + + - optionalDependencies에 있는 패키지들은 dependencies에 같은 이름이 있으면 덮어쓰게 되므로 한쪽에만 기재하는 것이 좋다. + + diff --git a/react-query/readme.md b/react-query/readme.md new file mode 100644 index 0000000..a18760f --- /dev/null +++ b/react-query/readme.md @@ -0,0 +1,26 @@ +## 리액트 쿼리 + + ### 단테 채널의 리액트 쿼리 사용하는 이유를 보고(https://www.youtube.com/watch?v=41tFNtwWE3o) + + - 서버에서 가져온 데이터를 브라우저에서 쉽게 사용할 수 있도록 돕는 도 + + - 서버에서 가져온 데이터를 "server state"라고 한다. + + - client state는 크게 두가지로 나눌 수 있다. + + 1. client 자체적으로 만드는 state(최초 데이터의 발생지가 클라이언트) + + 2. server에서 전달받은 값으로 만드는 state(최초 데이터의 발생지가 서버) + + - 1번의 경우(클라이언트가 자체적으로 만드는 state), 보통 UI를 담당한다. 가령 버튼이 클릭되었는지, 어떤 것이 클릭되었는지에 대한 메타 정보를 담은 상태값을 나타낸다. + + - 2번의 경우, 주식이나 코인과 같이 실시간 데이터가 중요한 서비스에서 더욱 중요하게 되었다. + + - 이러한 상황에서 가령 5초 뒤 데이터는 더 이상 유효하지 않은 낡은 데이터라고 한다면 클라이언트에서 polling 방식으로 주기적으로 데이터를 받아오거나(setInerval) a 페이지의 특정 컴포넌트에서 불러온 데이터를 페이지 전환하여 b 페이지에서 재사용하는 경우에도 용이하다. + + 리액트 쿼리는 데이터의 캐시 처리를 간편하게 할 수 있는 인터페이스를 제공한다. + - 특정 시간 이후, 데이터가 유효하지 않은 것으로 간주하고 새로운 데이터를 불러온다. + - 데이터에 변경점이 있는 경우에만 리렌더링을 유발한다. + - 유저가 탭을 이동했다가 다시 돌아왔을 때 데이터를 다시 불러온다. + - 데이터를 다시 호출할 때 응답이 오기 전까지는 이전 데이터를 계속 보여준다. 필요에 따라서는 로딩바와 같은 UI를 보여주기 위해 loading state를 기본적으로 제공한다. + diff --git a/react/mistake.md b/react/mistake.md new file mode 100644 index 0000000..1677cf6 --- /dev/null +++ b/react/mistake.md @@ -0,0 +1,25 @@ +react를 하며 겪은 실수들을 올립니다. + +* removeEventListener 관련 + + - useEffect에서 조건에 따라 listener를 추가하고 삭제해줘야 했었는데, 아무리 removeEventListener를 해도 삭제 되지 않는 상황이였다. + + ``` + const someFunc = () => { + ... + }; + + useEffect(() => { + if (조건) { + window.addEventListener("click", someFunc); + } else { + window.removeEventListener("click", someFunc); + } + }, []); + ``` + + - 찾아보니 someFunc가 동일한 함수로 인식되지 않는 것이였다. 즉 someFunc가 계속해서 생성되어 다른 함수로 인식되고 있는 상황이 문제였다. + + 그래서 해당 함수인 someFunc를 useCallback으로 감싸주어 함수가 재생성 되는 것을 방지하여 정상적으로 이벤트를 remove 할 수 있었다. + + cf) https://owldev.netlify.app/react/removeeventlistener/ diff --git a/react/readme.md b/react/readme.md new file mode 100644 index 0000000..a7e9aee --- /dev/null +++ b/react/readme.md @@ -0,0 +1,162 @@ +* debounce in react + + cf) https://www.developerway.com/posts/debouncing-in-react?utm_source=reactdigest&utm_medium&utm_campaign=1473 + +* React 18 + + cf) https://tech.osci.kr/2022/05/03/react-18v/ + +* Recoil, react-query + +image + + +* Prop Drilling(프로퍼티 내리꽂기)이란? + + - Prop Drilling은 props를 오로지 하위 컴포넌트로 전달하는 용도로만 쓰이는 컴포넌트들을 거치면서 React Component 트리의 한 부분에서 다른 부분으로 데이터를 전달하는 과정을 뜻한다. + + - prop drilling은 문제가 되지 않는다, 그러나 prop 전달을 10개, 15개 같이 많은 컴포넌트를 거쳐 전달하게 된다면, 코드를 읽을 때 해당 prop을 추적하기가 힘들어져 유지 보수에 매우 어려워 진다. + + - 이러한 Prop Drilling을 피하기 위해서 아래와 같은 방법들이 있다. + + * 전역 상태관리 라이브러리 사용 + + - redux, mobx, recoil 등 + + * 하위 컴포넌트를 출력하는 children 기능 사용 + + - 컴포넌트 자식으로 어떤 엘리먼트가 들어올 지 예상할 수 없는 경우, 범용적인 '박스'역할을 하는 sidebar 혹인 Dialog, layout과 같은 컴포넌트에서 자주 볼 수 있다. + + - children 사용 시, 컴포넌트 하위의 자식을 모두 자식 취급하지는 않는다고 한다. 코드를 통해 살펴보자. 아래의 코드에서 Category 컴포넌트의 자식의 개수를 확인해보면 1개만 출력된다고 한다. + + ``` + +
    + { + menuList.map((menu, idx) => { + return ( +
  • + { menu } +
  • + ) + }) + } +
+
+ ``` + + cf) + + 1. https://javascript.plainenglish.io/how-to-avoid-prop-drilling-in-react-using-component-composition-c42adfcdde1b + + 2. https://edykim.com/ko/post/prop-drilling/ + +* useReducer + + - useState의 대체함수 + + - (state, action) => newState의 형태로 reducer를 받고 dispatch 메서드와 짝의 형태로 현재 state를 반환. + + - 다수의 하윗값을 포함하는 복잡한 정적 로직을 만드는 경우, 다음 state가 이전 state에 의존적인 경우, 보통 useState보다 useReducer를 선호한다. + + - useReducer는 자세한 업데이트를 트리거하는 컴포넌트의 성능을 최적화할 수 있게 하는데, 이것은 콜백 대신 dispatch를 전달할 수 있기 때문이다. + +
+ +* npm outdated: 프로젝트에 설치되어 있는 라이브러리의 현재 버젼과 최신 버젼을 보여준다. 주기적으로 해당 명령어를 실행하여 버전 업데이트를 할 수 있도록 하는 것이 좋다. + +
+ +* redux + + - 액션과 리듀서가 서로 다른 파일에 정의되어 있을 수 있는데, 이럴 경우 개발하는데 불편하다. 그래서 리듀서와 액션 관련 코드들을 하나의 파일에 몰아서 작성하는 것을 'Ducks 패턴'이라고 한다. + + - Ducks 패턴을 따를 때는 액션의 이름에 접두사를 넣는다. 이렇게 하여 다른 모듈과 액션 이름이 중복되는 것을 방지할 수 있다. + + - 프리젠테이셔널 컴포넌트: 리덕스 스토어에 직접적으로 접근하지 않고 필요한 값 또는 함수를 props로만 받아와서 사용하는 컴포넌트. 주로 UI를 선언하는 것에 집중. + + - 컨테이너 컴포넌틍: 리덕스 스토어의 상태를 조회하거나, 액션을 디스패치할 수 있는 컴포넌트를 의미. HTML 태그를 사용하지 않고 다른 프레젠테이셔널 컴포넌트들을 불러와서 사용한다. + + - useSelector: 리덕스 스토어의 상태를 조회하는 Hook + + - useDispatch: 리덕스 스토어의 dispatch를 함수에서 사용할 수 있게 해주는 Hook. + + - connect함수: 컨테이너 컴포넌트를 만드는 방법. But useSelector, useDispatch가 워낙 편하여 해당 함수를 사용할 필요없어짐. 이 함수는 HOC(Higher-Order Component)이다. 이는 리액트 컴포넌트를 개발하는 하나의 패턴이고, 컴포넌트의 로직을 재활용할 때 유용한 패턴이다. HOC의 용도는 "컴포넌트를 특정 함수로 감싸서 특정 값 또는 함수를 props로 받아와서 사용할 수 있게 해주는 패턴"이다. + + ``` + export default connect( + mapStateToProps, + mapDispatchToProps + )(CounterContainer) + 위 코드는 아래와 동일하다. + + const enhance = connect(mapStateToProps, mapDispatchToProps); + export default enhance(CounterContainer); + ``` + +
+ +* useEffect() + + - useEffect() 함수에 async를 붙여서 사용할 수 없다? + + -> async/await 함수는 Promise 객체를 return 하기때문에 부수효과 함수가 될 수 없다고 한다. + + -> 부수효과 함수는 함수만 return할 수 있으며, 반환된 함수는 부수효과 함수가 호출되기 직전과 컴포넌트가 사라지기 직전에 호출된다. + + => useEffect 훅에서 async/await 함수를 사용하는 한 가지 방법은 부수효과 함수 내에서 async/await 함수를 만들어서 호출하는 것이라고 한다. + + +
+ +* 부수효과 함수란? + + - 부수효과란 외부의 상태를 변경하는 것을 의미(서버 API를 호출하거나, 이밴트 핸드러를 등록하는 것) + + - 부수효과가 많은 프로젝트는, 순수 함수가 가지는 여러 장점을 포기하게 되는 등, 유닛테스트가 힘들어진다. + + ``` + useEffect(() => {}, [variables]); + + 첫번째 매개변수 이 함수는 컴포넌트가 랜더링된 "후"에 호출된다. 더 정확하게, 렌더링 결과가 실제 돔에 반영되고 비동기로 호출된다. 이 함수를 부수 효과 함수라고 한다. + ``` + + - 부수효과 함수의 반환값은 항상 "함수 타입"이여야 한다. 따라서 useEffect의 첫번째 인자로 async함수를 사용할 수 없다. async 함수는 Promise 객체를 반환하기 때문에 부수함수 효과가 될 수 없다. 대신에 첫번째 인자 함수 내에서 async 함수를 호출하는 것은 가능하다. + + ``` + //(1) + useEffect(() => { + async function fetchUserInfo() { + const data = await fetchUserData(userId); + setUser(data); + } + }, [userId]); + + + //(2) + async function fetchUserInfo() { + const data = await fetchUserData(userId); + setUser(data); + } + + useEffect(() => { fetchUserInfo() }, [fetchUserInfo]); + + + //(3) + const fetchAndSetUser = useCallback( + async function fetchUserInfo() { + const data = await fetchUserData(userId); + setUser(data); + }, + [userId] + ); + + useEffect(() => { fetchAndSetUser() }, [fetchAndSetUser]); + + ``` + + - 2번과 같이 외부 함수를 useEffect 내부에서 호출하는 경우, useEffect의 두번째 인자인 의존성 배열에 함수명을 넣어줘어야 한다. + + - 그런데 2번 같은 경우 컴포넌트가 재렌더링 될 때마다, fetchUserInfo라는 함수가 계속해서 반복생성 되는 문제가 있어 3번 처럼 호출하는 함수에 useCallback을 감싸줘야 한다. diff --git a/testing/a/b_test.md b/testing/a/b_test.md new file mode 100644 index 0000000..e879acc --- /dev/null +++ b/testing/a/b_test.md @@ -0,0 +1 @@ +https://datarian.io/blog/a-b-testing diff --git a/todo/readme.md b/todo/readme.md new file mode 100644 index 0000000..f6b93c2 --- /dev/null +++ b/todo/readme.md @@ -0,0 +1,214 @@ +* 추후 정리할 내용입니다. + + [some article] + - https://velog.io/@broccoliindb/onBlur-on-react + + - https://drmutterl.tistory.com/entry/React-%ED%8F%B4%EB%8D%94-%EA%B5%AC%EC%A1%B0-%EC%9E%90%EC%A3%BC-%EC%93%B0%EB%8A%94-%ED%8F%B4%EB%8D%94%EB%AA%85 + + - https://velog.io/@jch9537/React-manifest.json + + - https://dev-event.vercel.app/events + + - https://portfolio.blogzip.net/ + + - https://devowen.com/453 + + - https://schatz37.tistory.com/2 + + - https://stackoverflow.com/questions/3397113/how-to-remove-focus-border-outline-around-text-input-boxes-chrome + + - https://intro.f-lab.kr/?utm_source=gdn&utm_medium=da_smart&utm_campaign=co_mentee&utm_content=Responsive&gclid=EAIaIQobChMIhZfr5-Kg_AIVM-L9BR36sgsGEAEYASAAEgJxp_D_BwE + + - https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=happylight&logNo=221412576943 + + - react 내에서도 vue의 watch 같은 유사한 기능을 구현해주는 것 - https://react-hook-form.com/api/useform/watch/ + + - chatGPT: https://www.btcc.com/ko-KR/academy/crypto-basics/what-is-chatgpt + + - 코파일럿: https://namu.wiki/w/GitHub%20Copilot + + [SD(Server-Driven) ui] + + - https://brunch.co.kr/@advisor/37 + + [개발 글쓰기] + + - https://www.youtube.com/watch?v=xu3XGEomRWI + + [react query] + + - https://www.youtube.com/watch?v=MArE6Hy371c + + [swr] + + - https://www.youtube.com/watch?v=b7Uqx7NZpHw + + [rtk 실전] + + - https://www.youtube.com/watch?v=pnpO3o8mLBU19a770002fe6afb80e7383db008c26a55f811896 + + + [addEventListener('scroll') VS onScroll Event] + + - https://stackoverflow.com/questions/60745475/what-is-the-difference-between-window-onscroll-and-window-addeventlistener + + [지디웹] + + - https://www.gdweb.co.kr/main/ + + + [log 관리 ELKR] + + - +https://medium.com/chequer/elkr-elasticsearch-logstash-kibana-redis-%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%A1%9C%EA%B7%B8%EB%B6%84%EC%84%9D-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-f3dd9dfae622 + + - https://blog.advenoh.pe.kr/go/Go%EC%97%90%EC%84%9C%EC%9D%98-%EB%A1%9C%EA%B7%B8%EA%B9%85-Logging-in-Go/ + + - https://jonnung.dev/system/2018/04/06/fluentd-log-collector-part1/#gsc.tab=0 + + - https://coding-factory.tistory.com/801 + + + [PoC란?] + + - https://engineer-mole.tistory.com/35 + + [semantic UI] + + - https://geonlee.tistory.com/96 + + [mouse 이벤트] + + - https://yoonsidae.tistory.com/13 + + - https://velog.io/@rimo09/%EB%A7%88%EC%9A%B0%EC%8A%A4-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%A0%95%EB%B3%B5 + + - https://songjihyeon.tistory.com/22 + + [svg handle] + + - https://velog.io/@juno7803/React-React%EC%97%90%EC%84%9C-SVG-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0 + + [page] + + * 404 Page + + - https://velog.io/@juno7803/!https://blog.logrocket.com/how-to-use-svgs-in-react/ + + + [알고리즘] + + - https://school.programmers.co.kr/learn/courses/30/parts/12263 + + - https://school.programmers.co.kr/learn/challenges?tab=algorithm_practice_kit + + [github 잔디] + + - https://pearlluck.tistory.com/365 + + - https://coding-groot.tistory.com/109 + + - https://jamesu.dev/posts/2021/02/09/showing-github-contributions-graph/ + + + [vscode 기능] + + - https://www.youtube.com/watch?v=mh-0twurNRE + + - https://ux.stories.pe.kr/150 + + [rollup VS webpack] + + - https://yoon-dumbo.tistory.com/entry/%EB%A1%A4%EC%97%85%EA%B3%BC-%EC%9B%B9%ED%8C%A9%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90-rollup-vs-webpack + + [craco] + + - https://abangpa1ace.tistory.com/220#:~:text=%F0%9F%92%99%20Craco%20%EB%9E%80%3F,%EB%8D%AE%EC%96%B4%EC%93%B0%EA%B8%B0%20%EC%9C%84%ED%95%9C%20%ED%8C%A8%ED%82%A4%EC%A7%80%EC%9D%B4%EB%8B%A4 + + - https://bgradecoding.tistory.com/14 + + [nexjs] + + - https://velog.io/@kjs2504/Next.js-%EB%B8%94%EB%A1%9C%EA%B7%B8 + + - https://darrengwon.tistory.com/833 + + [resume] + + - https://wonny-log.notion.site/Wonny-c2f8051bfb574f349406a30d2bc71a45 + + [js의 contextMenu란] + + - https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event + + [flex 속성] + + - 프엔 개발자로서 어떤 퍼블리싱이건 간에 마스터하고 싶은 마음에 + + - https://flexboxfroggy.com/#ko + + - https://d2.naver.com/helloworld/8540176 + + - https://velog.io/@mooongs/flex1%EC%9D%98-%EC%9D%98%EB%AF%B8 + + // udemy 강의가 좋긴 한 것 같다. + + [cypress] + + - https://www.cypress.io/ + + - https://velog.io/@0307kwon/cypress%EB%9E%80 + + [2023 tech trend] + + - https://www.youtube.com/watch?v=1v_TEnpqHXE + + + [react-docker] + + - https://velog.io/@shinyejin0212/React-2.-Docker%EB%A1%9C-React-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0 + + + [try-catch] + + // 비동기 함수 작성 시 try-catch로 감싸주기 VS await에서 제공하는 .catch로 에러 처리하기 + + - https://velog.io/@vraimentres/async-%ED%95%A8%EC%88%98%EC%99%80-try-catch + + [nextjs] + + - https://velog.io/@taeung/Next.js-getStaticProps-%EC%82%AC%EC%9A%A9%EA%B8%B0 + + - https://merrily-code.tistory.com/154 + + + [eslint] + + - https://talkwithcode.tistory.com/93 + + - https://heewon26.tistory.com/262 + + - https://helloinyong.tistory.com/325 + + - https://tech.kakao.com/2019/12/05/make-better-use-of-eslint/ + + + [peerDependency] + + - https://bohyeon-n.github.io/deploy/etc/peerdependencies.html#:~:text=The%20solution%3A%20Peer%20Dependencies&text=dependency%EB%8A%94%20%EB%82%B4%EA%B0%80%20%EB%A7%8C%EB%93%A0%20%EB%AA%A8%EB%93%88,%ED%98%B8%ED%99%98%EC%84%B1%EC%9D%84%20%ED%91%9C%EC%8B%9C%ED%95%98%EB%8A%94%20%EA%B2%83%EC%9D%B4%EB%8B%A4. + + - https://www.zerocho.com/category/NodeJS/post/5825a3caaff5c70018279975 + + [유익한 사이트] + + - https://frontend-master-library.vercel.app/ + + - https://egg-programmer.tistory.com/295 + + - https://inpa.tistory.com/entry/VS-Code-%E2%8F%B1%EF%B8%8F-%EC%BD%94%EB%94%A9%EC%97%90-%EC%9C%A0%EC%9A%A9%ED%95%9C-%EB%8F%84%EA%B5%AC-%EC%B6%94%EC%B2%9C + + - https://www.notion.so/201ff4f777a94e05b79d20d370c455c4 + + - https://github.com/codingmonster-tv/Awesome_Resume_Portfolio + + - https://egg-programmer.tistory.com/259 diff --git a/todo/turnover.md b/todo/turnover.md new file mode 100644 index 0000000..f67bef8 --- /dev/null +++ b/todo/turnover.md @@ -0,0 +1,51 @@ +## 📌가고 싶은 회사의 티어를 메길 것 + +#### *아래 내용 나만의 언어로 정리할 것* + + - 1티어: 언젠가는 반드시 갈 회사 + + - 2티어: 1티어 보다 약하지만 괜찮은 회사 + + - 3티어: 지금보다는 좋은 회사 + + + #### 1,2,3 티어 회사의 기술 스택 조사 + + - 비슷한 기술을 사용하는 회사 찾기 + - 회사에서 사용하는 기술을 바로 잘 사용하는 실무자를 원함 + + +## 📌good company? + + - 성장과 연봉의 관점 + - 개발, 운영, 개선을 모두 경험해볼 수 있는 곳: 내가 만든 코드를 내가 운영하고 개선하는 것 + - 본인 제품을 만드는 회사 + + +## 📌채용 + + - 채용은 확률
+ → 기술 경험과 성장 가능성이 돋보여야 한다
+ → 티어가 높은 회사는 평균 기대치가 높다 + + - 실력있는 개발자에 대해서는 TO가 무제한이다
+ → 현재 채용은 한 명의 실력 있는 개발자를 데려가기 위해 여러 회사가 채용 전쟁을 벌이고 있다. + + +## 📌 이력서 + + - 서류탈락
+ → 이직 실력과 경험이 해당 티어에 가기에는 부족 + - 기대치를 낮추고 회사 티어를 더 낮추어야 한다. + - 학습과 경험을 더 쌓아야 한다. + + - 실력은 있지만 이력서 작성 방법 부족 + - 나쁜 케이스: 프로젝트만 나열 + - 이력서 잘 쓰는 방법도 찾아서 공부해야함 + + - 필살기
+ → 기술 면접관을 낚는 마법의 단어(“문제와 해결“)
+ → 프로그래머 = 문제해결사 / 문제는 풀어야 하고, 해결 방법이 궁금하다.
+ → 프로젝트에서 있었던 문제 - 그리고 해결을 녹일 것(프론트에서 관심 갖을 문제를 쓰자, 그리고 내 태도를 보일 수 있는 것을 녹이자) + + -> 문제를 기술적으로 어떻게 해결했는지 자세히 적는다. diff --git a/typescript/.gitignore b/typescript/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/typescript/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git "a/typescript/10.\354\240\234\353\204\244\353\246\255.md" "b/typescript/10.\354\240\234\353\204\244\353\246\255.md" deleted file mode 100644 index 59a2892..0000000 --- "a/typescript/10.\354\240\234\353\204\244\353\246\255.md" +++ /dev/null @@ -1,46 +0,0 @@ -* 제네릭 소개 - - - -* 제네릭의 기본 문법 - - - -* 기존 타입 정의 방식과 제네릭의 차이점 - 함수 중복 선언의 단점 - - - -* 기존 문법과 제네릭의 차이점 - 유니온 타입을 이용한 선언 방식의 문제점 - - - -* 제네릭의 장점과 타입 추론에서의 이점 - - - -* 제네릭 실전 예제 살펴보기 - 예제 설명 - - - -* 제네릭 실전 예제 살펴보기 - 코드에 타입 정의하기 - - -* 인터페이스에 제네릭을 선언하는 방법 - - - -* 제네릭 실전 예제 살펴보기 - 제네릭을 이용한 타입 정의 - - - -* 제네릭의 타입 제한 - - - -* 정의된 타입으로 타입을 제한하기 - - - -* keyof로 제네릭의 타입 제한하기 - - diff --git "a/typescript/12.\355\203\200\354\236\205\354\266\224\353\241\240.md" "b/typescript/12.\355\203\200\354\236\205\354\266\224\353\241\240.md" deleted file mode 100644 index 400c655..0000000 --- "a/typescript/12.\355\203\200\354\236\205\354\266\224\353\241\240.md" +++ /dev/null @@ -1,13 +0,0 @@ -* 타입 추론 소개 - - -* 인터페이스와 제네릭을 이용한 타입 추론 방식 - - -* 복잡한 구조에서의 타입 추론 방식 - - -* Best Common Type 추론 방식 - - -* Typescript Language Server 소개 diff --git "a/typescript/13.\355\203\200\354\236\205\353\213\250\354\226\270.md" "b/typescript/13.\355\203\200\354\236\205\353\213\250\354\226\270.md" deleted file mode 100644 index f1dbdef..0000000 --- "a/typescript/13.\355\203\200\354\236\205\353\213\250\354\226\270.md" +++ /dev/null @@ -1,4 +0,0 @@ -* 타입 단언 소개 - - -* 타입 단언 예제 diff --git "a/typescript/14.\355\203\200\354\236\205\352\260\200\353\223\234.md" "b/typescript/14.\355\203\200\354\236\205\352\260\200\353\223\234.md" deleted file mode 100644 index c197f6a..0000000 --- "a/typescript/14.\355\203\200\354\236\205\352\260\200\353\223\234.md" +++ /dev/null @@ -1,5 +0,0 @@ -* 타입 가드를 위한 예제 소개 - - - -* 타입 가드 소개와 적용 diff --git "a/typescript/15.\355\203\200\354\236\205\355\230\270\355\231\230.md" "b/typescript/15.\355\203\200\354\236\205\355\230\270\355\231\230.md" deleted file mode 100644 index b8f9b2b..0000000 --- "a/typescript/15.\355\203\200\354\236\205\355\230\270\355\231\230.md" +++ /dev/null @@ -1,7 +0,0 @@ -* 타입 호환이란? - - -* 타입 호환 예제 - 인터페이스, 클래스 - - -* 타입 호환 예제 - 함수, 제네릭 diff --git "a/typescript/16.\355\203\200\354\236\205\353\252\250\353\223\210\355\231\224.md" "b/typescript/16.\355\203\200\354\236\205\353\252\250\353\223\210\355\231\224.md" deleted file mode 100644 index 490d711..0000000 --- "a/typescript/16.\355\203\200\354\236\205\353\252\250\353\223\210\355\231\224.md" +++ /dev/null @@ -1,10 +0,0 @@ -* 타입스크립트의 모듈 시스템 - - -* 자바스크립트의 모듈 시스템 - - -* 전화번호부 애플리케이션 모듈화 실습해보기 - - -* 전화번호부 애플리케이션 실습 풀이 diff --git "a/typescript/4.\355\225\240\354\235\274-\352\264\200\353\246\254-\354\225\240\355\224\214\353\246\254\354\274\200\354\235\264\354\205\230.md" "b/typescript/4.\355\225\240\354\235\274-\352\264\200\353\246\254-\354\225\240\355\224\214\353\246\254\354\274\200\354\235\264\354\205\230.md" deleted file mode 100644 index e69de29..0000000 diff --git "a/typescript/5.\354\235\270\355\204\260\355\216\230\354\235\264\354\212\244.md" "b/typescript/5.\354\235\270\355\204\260\355\216\230\354\235\264\354\212\244.md" deleted file mode 100644 index 922da75..0000000 --- "a/typescript/5.\354\235\270\355\204\260\355\216\230\354\235\264\354\212\244.md" +++ /dev/null @@ -1,19 +0,0 @@ -* 인터페이스 소개 및 변수를 정의하는 인터페이스 - - -* 함수의 인자를 정의하는 인터페이스 - - -* 함수 구조를 정의하는 인터페이스 - - -* 인덱싱 방식을 정의하는 인터페이스 - - -* 인터페이스 딕셔너리 패턴 - - -* 인터페이스 확장(상속) - - - diff --git "a/typescript/6.\355\203\200\354\236\205\353\263\204\354\271\255.md" "b/typescript/6.\355\203\200\354\236\205\353\263\204\354\271\255.md" deleted file mode 100644 index 76060a4..0000000 --- "a/typescript/6.\355\203\200\354\236\205\353\263\204\354\271\255.md" +++ /dev/null @@ -1,12 +0,0 @@ -* 타입 별칭 소개 - - - -* 타입 별칭 코드 예제 - - - -* 타입 별칭과 인터페이스 차이점 - - - diff --git "a/typescript/7.\354\227\260\354\202\260\354\236\220\353\245\274-\354\235\264\354\232\251\355\225\234-\355\203\200\354\236\205\354\240\225\354\235\230.md" "b/typescript/7.\354\227\260\354\202\260\354\236\220\353\245\274-\354\235\264\354\232\251\355\225\234-\355\203\200\354\236\205\354\240\225\354\235\230.md" deleted file mode 100644 index a4ad5f0..0000000 --- "a/typescript/7.\354\227\260\354\202\260\354\236\220\353\245\274-\354\235\264\354\232\251\355\225\234-\355\203\200\354\236\205\354\240\225\354\235\230.md" +++ /dev/null @@ -1,17 +0,0 @@ -* 연산자를 이용한 타입 정의 - Union Type - - - -* 유니온 타입의 장점 - - -* 유니온 타입의 특징 - - -* 인터섹션 타입 소개 - - -* 유니온 타입과 인터섹션 타입의 차이점 - - - diff --git "a/typescript/8.\354\235\264\353\204\230.md" "b/typescript/8.\354\235\264\353\204\230.md" deleted file mode 100644 index ef39dba..0000000 --- "a/typescript/8.\354\235\264\353\204\230.md" +++ /dev/null @@ -1,13 +0,0 @@ -* 이넘 소개 - - -* 숫자형 이넘 - - -* 문자형 이넘 - - -* 이넘 활용 사례 - - - diff --git "a/typescript/9.\355\201\264\353\236\230\354\212\244.md" "b/typescript/9.\355\201\264\353\236\230\354\212\244.md" deleted file mode 100644 index ef8e80e..0000000 --- "a/typescript/9.\355\201\264\353\236\230\354\212\244.md" +++ /dev/null @@ -1,17 +0,0 @@ -* 클래스 소개 - - - -* 자바스크립트 프로토타입 소개 - - - -* 자바스크립트 프로토타입의 활용 사례 - - - -* 프로토타입과 클래스와의 관계 - - - -* 타입스크립트의 클래스 문법 diff --git a/typescript/error.md b/typescript/error.md new file mode 100644 index 0000000..51d0739 --- /dev/null +++ b/typescript/error.md @@ -0,0 +1,15 @@ +## 타입스크립 관련 에러 작성 모음 + +### Operator '+' cannot be applied to types 'Number' and 'Number'. + + - 숫자 타입인 값을 연산하다 위와 같은 에러가 출려되었다. + + - 숫자 타입은 Number 타입과 number 타입으로 나뉘는데, Number 타입은 `non-primitive type`이기에 더하기 연산(+, 다른 연산도 마찬가지)이 불가능하다. + + - 대신 number라는 `primitive type`으로 연산을 진행해야 한다. + + - cf) 숫자 타입에 대해서 정수로만, 양수로만 입력가능하게 하는 방법 + + - https://velog.io/@vraimentres/ts-integer + + - But, 실무에서는 사용하기 어려운 컨셉. 의도된 기능을 정확하게 구현하지 못하기에, 다시금 validation하는 과정이 필요한 상황이라고 한다.. diff --git a/typescript/hello.js b/typescript/hello.js new file mode 100644 index 0000000..7af74c2 --- /dev/null +++ b/typescript/hello.js @@ -0,0 +1,5 @@ +function concat(left, right) { + return left + right; +} +var hello = concat("hello", "world"); +console.log(hello); diff --git a/typescript/hello.ts b/typescript/hello.ts new file mode 100644 index 0000000..6f9b719 --- /dev/null +++ b/typescript/hello.ts @@ -0,0 +1,10 @@ +function concat(left:string , right:string):string{ + + return left+right; + + } + + + let hello:string = concat("hello", "world"); + + console.log(hello); \ No newline at end of file diff --git "a/typescript/1.\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270-\354\206\214\352\260\234-\353\260\260\352\262\275.md" "b/typescript/lecture/01.\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270-\354\206\214\352\260\234-\353\260\260\352\262\275.md" similarity index 100% rename from "typescript/1.\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270-\354\206\214\352\260\234-\353\260\260\352\262\275.md" rename to "typescript/lecture/01.\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270-\354\206\214\352\260\234-\353\260\260\352\262\275.md" diff --git "a/typescript/2.\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270-\354\213\234\354\236\221\355\225\230\352\270\260.md" "b/typescript/lecture/02.\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270-\354\213\234\354\236\221\355\225\230\352\270\260.md" similarity index 100% rename from "typescript/2.\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270-\354\213\234\354\236\221\355\225\230\352\270\260.md" rename to "typescript/lecture/02.\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270-\354\213\234\354\236\221\355\225\230\352\270\260.md" diff --git "a/typescript/3.\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270-\352\270\260\354\264\210-\353\263\200\354\210\230,\355\225\250\354\210\230-\355\203\200\354\236\205\354\240\225\354\235\230.md" "b/typescript/lecture/03.\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270-\352\270\260\354\264\210-\353\263\200\354\210\230,\355\225\250\354\210\230-\355\203\200\354\236\205\354\240\225\354\235\230.md" similarity index 100% rename from "typescript/3.\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270-\352\270\260\354\264\210-\353\263\200\354\210\230,\355\225\250\354\210\230-\355\203\200\354\236\205\354\240\225\354\235\230.md" rename to "typescript/lecture/03.\355\203\200\354\236\205\354\212\244\355\201\254\353\246\275\355\212\270-\352\270\260\354\264\210-\353\263\200\354\210\230,\355\225\250\354\210\230-\355\203\200\354\236\205\354\240\225\354\235\230.md" diff --git "a/typescript/lecture/04.\355\225\240\354\235\274-\352\264\200\353\246\254-\354\225\240\355\224\214\353\246\254\354\274\200\354\235\264\354\205\230.md" "b/typescript/lecture/04.\355\225\240\354\235\274-\352\264\200\353\246\254-\354\225\240\355\224\214\353\246\254\354\274\200\354\235\264\354\205\230.md" new file mode 100644 index 0000000..cadee12 --- /dev/null +++ "b/typescript/lecture/04.\355\225\240\354\235\274-\352\264\200\353\246\254-\354\225\240\355\224\214\353\246\254\354\274\200\354\235\264\354\205\230.md" @@ -0,0 +1,51 @@ +* any, void 소개 + + - tsconfig.js: 타입스크립트 설정 파일 + + - any: 기존 자바스크립트에서 실행 시점에 타입을 구분하여 타입을 할당해주는 성질과 동일하다. 그래서 모든 타입의 값을 any 타입 변수에 할당 가능하다. + + - js 프로젝트에 ts를 적용한다고 하면 모든 타입에 any를 적용하고 나서 추후에 타입을 구체적으로 바꿔나는 것이 정석적인 방법 + + ``` + function addTodo(todo): void { // return 하는 것이 없는 경우 명시적으로 void를 써줄 것 + todoItems.push(todo); + } + ``` + + - todo 객체 내에 done이라는 속성이 존재하지만 todo 객체를 사용하는 함수에서는 done 속성이 존재하는 지 모르기에 아래와 같이 에러가 밑줄 그어진다. + + ![image](https://user-images.githubusercontent.com/53415000/147844425-9fe51ac5-38b5-4818-a670-08fddd06cc56.png) + + ![image](https://user-images.githubusercontent.com/53415000/147844388-4c2ae2a3-d2f3-49a1-a7ce-6eef0aede773.png) + + 따라서 위 todo 객체를 선언할 때 구체적으로 선언해주는 과정이 필요하다. + + ![image](https://user-images.githubusercontent.com/53415000/147844452-e1b973cb-95ff-48e4-b680-f9b6c6050d17.png) + + ![image](https://user-images.githubusercontent.com/53415000/147844462-62f6e45f-e8b7-4759-ab7e-5b9e1b919d86.png) + + + 그런데 위 코드를 보면 아래의 코드가 많이 반복된다. + + ``` + { id: number, title: string, done: Boolean } + ``` + + 따라서 이 중복되는 코드를 해결하기 위해선 2가지 방법이 있다고 한다. + + 1. type 별칭 + 2. 인터페이스 + + 타입 별칭 + + ![image](https://user-images.githubusercontent.com/53415000/147844488-39e012d1-604b-46e3-a7e4-8b3cab1e7b07.png) + + 와 같이 type을 선언하여 해당 타입으로 타입을 설정하는 것이다. + + 인터페이스 + + ![image](https://user-images.githubusercontent.com/53415000/147844508-db3ac53a-f12f-44d1-8d99-51716f51f35a.png) + + 와 같이 interface를 선언하여 타입을 선언하는 것인데, type 별칭과는 크게 사용법은 다르지 않는 것 같다. 다만 interface 같은 경우는 ts에서 핵심 기능이라고 한다. + + diff --git "a/typescript/lecture/05.\354\235\270\355\204\260\355\216\230\354\235\264\354\212\244.md" "b/typescript/lecture/05.\354\235\270\355\204\260\355\216\230\354\235\264\354\212\244.md" new file mode 100644 index 0000000..36f0b82 --- /dev/null +++ "b/typescript/lecture/05.\354\235\270\355\204\260\355\216\230\354\235\264\354\212\244.md" @@ -0,0 +1,115 @@ +* 인터페이스 소개 및 변수를 정의하는 인터페이스 + + ``` + interface User { + age: number, + name: string, + } + + // 변수에 인터페이스 활용 + let seho: User = { // seho를User 타입으로 선언했을 경우 User 타입에 해당하는 속성인 age와 name을 선언해줘야 한다. + age: 33, + name: "seho", + } + + // 함수에 인터페이스 활용 + function getUser(user) { + .... + } + + 위와 같이 선언해줬을 경우, 어떤 타입의 파라미터이든 getUser의 전달인자로 들어갈 수 있게된다. 따라서 User 타입의 전달인자만 넣게 하려면 아래와 같이 해야한다. + + function getUser(user: User) { + ... + } + + 만약 아래와 같은 변수를 위 getUser함수에 전달인자로 보내면 에러가 발생한다. + + const capt = { + name: "캡틴" + } + + + ``` + + +* 함수의 인자를 정의하는 인터페이스 + + 위에서 설명 추가 + +
+ +* 함수 구조를 정의하는 인터페이스 + + ``` + // 함수의 스펙(구조)에 인터페이스를 활용 + // SumFunction 함수의 스펙을 설정 + // 해당 타입의 함수는 인자를 두개를 받으며 그 두 인자는 number 타입임을 명시하는 것, 그리고 반환 타입도 number 타입임을 나타내는 것:wq + interface SumFunction { + (a: number, b: number): number; + } + ``` + + +* 인덱싱 방식을 정의하는 인터페이스 + + ``` + interface StringArray { // index는 number, index에 해당하는 값은 string + [index: number]: string; + } + + let arr: StringArray = ["a", "b", "c"]; + + arr[0] = 10 // error + ``` + + +* 인터페이스 딕셔너리 패턴 + + ``` + interface StringRegexDictionary { + [key: string]: RegExp; + } + + let obj: StringRegexDictionary = { + cssFile: 'css' // 오류 출력, 정규표현식이 와야할 자리에 'css'라는 문자열이 왔기에. + cssFile: /\.css$/ //.css 확장자 파일을 가진 모든 파일을 들고 오는 정규식 + jsFile: /\.js$/ + } + + 인터페이스를 사용함으로써, 객체 내에 값을 생성할 때 정해진 방식대로의 값만을 넣을 수 있다. + ``` + +* 인터페이스 확장(상속) + + ``` + interface Person { + name: string; + age: number; + } + + interface Developer extends Person{ + language: string; + } + + + let capt: Developer = { // Developer 타입의 변수를 생성할 때는 Person 타입의 값들도 정의해야 한다. + language: 'ts', + age: 100, + name: "캡틴" + } + ``` + + + 선택적 프로퍼티 + + ![image](https://user-images.githubusercontent.com/53415000/150723194-0de5ba20-f7cc-479c-a3f5-75733419106f.png) + + cf 출처: https://www.heecheolman.dev/post/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4/ + +
+ 읽기 전용 프로퍼티 + + ![image](https://user-images.githubusercontent.com/53415000/150723427-f269fd25-d375-48a7-b810-72cfbb6fc169.png) + + cf 출처: https://www.heecheolman.dev/post/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4/ diff --git "a/typescript/lecture/06.\355\203\200\354\236\205\353\263\204\354\271\255.md" "b/typescript/lecture/06.\355\203\200\354\236\205\353\263\204\354\271\255.md" new file mode 100644 index 0000000..265bc2e --- /dev/null +++ "b/typescript/lecture/06.\355\203\200\354\236\205\353\263\204\354\271\255.md" @@ -0,0 +1,15 @@ +* 타입 별칭 소개 + + - 타입 별칭: 특정 타입이나 인터페이스를 참조할 수 있는 타입 변수를 의미. + + + +* 타입 별칭 코드 예제 + + + +* 타입 별칭과 인터페이스 차이점 + + - 타입 별칭과 인터페이스의 가장 큰 차이점은 타입의 확장 가능 / 불가능 여부이다. 인터페이스는 확장이 가능한데 반해 타입 별칭은 확장이 불가능하다. 따라서 가능한한 type 보다는 interface로 선언해서 사용하는 것을 추천(공식 페이지에서도 권장하는 내용)한다고 한다. + + cf) 좋은 소프트웨어는 언제나 확장이 용이해야한다는 원칙(https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle) diff --git "a/typescript/lecture/07.\354\227\260\354\202\260\354\236\220\353\245\274-\354\235\264\354\232\251\355\225\234-\355\203\200\354\236\205\354\240\225\354\235\230.md" "b/typescript/lecture/07.\354\227\260\354\202\260\354\236\220\353\245\274-\354\235\264\354\232\251\355\225\234-\355\203\200\354\236\205\354\240\225\354\235\230.md" new file mode 100644 index 0000000..aeacb48 --- /dev/null +++ "b/typescript/lecture/07.\354\227\260\354\202\260\354\236\220\353\245\274-\354\235\264\354\232\251\355\225\234-\355\203\200\354\236\205\354\240\225\354\235\230.md" @@ -0,0 +1,94 @@ +* 연산자를 이용한 타입 정의 - Union Type + + ``` + function logMessage(value: string | number) { // value는 string 혹은 number 타입이 될 수 있도록 한다. | 연산을 통해 여러 타입(하나 이상의)을 사용할 수 있도록 한다. | 를 union type이라고 한다. + console.log(value); + } + ``` + + +* 유니온 타입의 장점 + + ``` + fucntion logMessage(value: string | number) { + if (typeof value === 'number') { + value. 으로 접근했을 때 number에 관한 API 함수를 사용할 수 있도록 vscode에서 출력해준다. + } + if (typeof value === 'string') { + value. 으로 접근했을 때 마찬가지로 string에 관한 API 함수를 사용할 수 있도록 vscode에서 출력해준다. + } + throw new TypeError('value must be string or number'); + if 절로 타입의 범위를 추려가는 과정을 '타입 가드'라고 한다. + } + ``` + + // 타입 가드: 특정 타입으로 타입의 범위를 좁혀 나가는(필터링 하는) 과정 + + +* 유니온 타입의 특징 + ``` + interface Developer { + name: string; + skill: string; + } + + interface Person { + name: string; + age: number; + } + + function askSomeone(someone: Developer | Person) { + somone. 으로 접근했을 때 자동으로 출력되는 속성은 name 하나 뿐이다. + skill, age와 같은 속성을 접근할 수 있게 해주는 것은 type-safe하지 않은, 코드 상에서 에러가 충분히 날 수 있는 가능성이 있기에. 따라서 공통된 속성, 보장된 속성에 대해서만 제공을 한다. + } + + ``` + + +* 인터섹션 타입 소개 + + ``` + &으로 표현하는 인터섹션 타입 + + let capt: string & number & boolean // capt 위에 마우스를 올렸을 경우, capt는 Never 라는 타입을 띄운다. 곧, 절대 될 수 없는 타입이라는 것. string 이면서 number 이면서 boolean인 타입은 없다는 것을 뜻한다. + + function askSomeone(someone: Developer & Person) { // someone은 Developer, Person 내의 속성들을 모두 포함한 타입을 뜻한다. 따라서 아래와 같이 someone에 대해 name, skill, age에 대해 모두 접근할 수 있다. + + someone.name; + someone.skill; + someone.age; + } + + 유니언 타입에 경우에는 타입 가드를 통하여 타입을 추론해야하지만, intersection type에서는 이 과정을 생략할 수 있다. + + ``` + +* 유니온 타입과 인터섹션 타입의 차이점 + + 인터섹션 타입 + + ``` + function askSomeone(someone: Developer & Person) { + someone.name; + someone.skill; + someone.age; + } + + askSomeone({name: '디벨로퍼', skill: 'js'}) // 로 하면 error, Developer 타입이면서 Person 타입인 새로운 타입의 전달인자가 넘겨져야 한다. + askSomeone({name: '디벨로퍼', skill: 'js', age: 100}); // good + + ``` + + 유니언 타입 + ``` + function askSomeone(someone: Developer | Person) { + someone.name; + //someone.skill; + //someone.age; + } + + askSomeone({name: '디벨로퍼', skill: 'js'}) // good + askSomeone({name: '디벨로퍼', age: 100}) // good + + ``` + diff --git "a/typescript/lecture/08.\354\235\264\353\204\230.md" "b/typescript/lecture/08.\354\235\264\353\204\230.md" new file mode 100644 index 0000000..07cdbf5 --- /dev/null +++ "b/typescript/lecture/08.\354\235\264\353\204\230.md" @@ -0,0 +1,90 @@ +* 이넘 소개 + + - 이넘은 특정 값들의 집합을 의미하는 자료형 + + - 타입스크립트에서는 문자형 이넘과 숫자형 이넘을 지원한다. + + +* 숫자형 이넘 + + ``` + enum Shoes { + Nike, + Adidas + } + + // Shoes. 으로 접근했을 때 Nike, Adidas 속성에 접근할 수 있다. + + console.log(Shoes.Nike) // 0 출력 + + ``` + + +* 문자형 이넘 + + ``` + enum Shoes { + Nike = 10, // 과 같이 초기화, 정의해주지 않으면 숫자값 0 이 된다. + Adidas + } + + enum Shoes { + Nike = '나이키' + Adidas = '아디다스' + } + + let myShoes = Shoes.Nike; + console.log(myShoes); // 나이키 출력 + + ``` + + +* 이넘 활용 사례 + + ``` + function isAnswered(answer: string) { + if (answer === 'yes') { + console.log("정답"); + } + + if (answer === 'no') { + console.log("오답"); + } + } + + isAnswered('예스'); + isAnswered('y'); + isAnswered('Yes'); + + 등 과 같이 다양한 표현을 사용할 수 있는데, 구체적인 값으로 제한하는 것이 enum 이다. + + ``` + + ``` + enum Answer { + Yes = 'Y', + No = 'N' + } + + function isAnswered(answer: Answer) { + if (answer === Answer.Yes) { + console.log("정답"); + } + + if (answer === Answer.No) { + console.log("오답"); + } + } + + isAnswered(Answer.Yes) // good + isAnswered('Yes'); // error 출력 + + ``` + + 드롭 다운 등의 목록이 필요한 형태에서 이넘을 정의해 쓰는 것이 좋다. 정확한 코드, 예외 처리 케이스가 줄어드는 이점을 갖을 수 있다. + + + ![image](https://user-images.githubusercontent.com/53415000/150721645-412c3dc8-2462-4b12-9aa0-fcb466712cb4.png) + + cf 이미지 출처) https://www.heecheolman.dev/post/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-basic-types/ + diff --git "a/typescript/lecture/09.\355\201\264\353\236\230\354\212\244.md" "b/typescript/lecture/09.\355\201\264\353\236\230\354\212\244.md" new file mode 100644 index 0000000..90268dc --- /dev/null +++ "b/typescript/lecture/09.\355\201\264\353\236\230\354\212\244.md" @@ -0,0 +1,91 @@ +* 클래스 소개 + ``` + class Person { + // 클래스 로직 + // 클래스의 역할은 보통 인스턴스를 만들어 주기에 constructor를 생성한다. + + constructor(name, age) { // 초기화 메서드 + console.log("생성 되었습니다.") + + this.name = name; + this.age = age; + } + } + + let seho = new Person('세호', 30) // '생성 되었습니다' + console.log(seho); + + ``` + + +* 자바스크립트 프로토타입 소개 + + ``` + 객체 내 중복되는 속성들을 js의 프로토타입을 활용하여, 중복적으로 코드 작성하는 것을 피할 수 있다. + + let user = { name: "capt", age: 100 }; + + let admin = {}; + + admin.__proto__ = user; // admin의 prototype 상위에 user 객체를 주겠다는 것. 이때 부터 admin. 으로 접근 시 user 속성인 name과 age를 내려받아 재사용할 수 있게 된다. + + console.log(admin); // 빈 객체를 출력 but prototype에는 user의 속성이 들어가 있다. + ``` + + +* 자바스크립트 프로토타입의 활용 사례 + + ``` + let arr = []; + arr. 으로 접근했을 때, concat, fill, filter, flat, includes 등 과 같은 메서드를 사용할 수 있도록 자동적으로 띄워주는데, 이렇게 사용가능한 함수들 목록이 뜰 수 있는 것은 arr의 프로토 타입인(__proto__: Array(0)) Array에서 제공하는 것들이였기에 가능하다. 이런 것을 "Built-in Javascript API" 또는 "Javascript Native API"라고 한다. + + 프로토 타입을 통해 객체의 확장이 가능하며 default로 제공되는 기능들을 사용할 수 있다. + ``` + + + +* 프로토타입과 클래스와의 관계 + + ``` + function Person(name, age) { + this.name = name; + this.age = age; + } + + let capt = new Person('캡틴', 100); + + // 아래의 class 문법은 위와 동일한 코드이며, 문법적으로 편하게(=syntatic sugar) 하기 위해 class 문법을 제공한다고 한다. 클래스 문법을 지원하게 된 배경은 java 와 같은 객체 지향 언어에 익숙한 사람들이 js를 더 익숙하게 사용하게 하기 위해 클래스 기반 문법을 제공하였다. 하지만 class를 바벨로 돌려서 보면 실질적으로는 위 코드와 같이 생성자 함수를 사용했음을 알 수 있다. 결국 프로토 타입 기반의 상속은 유지되고 있다. 클래스 문법 사용 없이도 생성자함수를 만들 수 있다. + + class Person { + // 클래스 로직 + // 클래스의 역할은 보통 인스턴스를 만들어 주기에 constructor를 생성한다. + + constructor(name, age) { // 초기화 메서드 + console.log("생성 되었습니다.") + + this.name = name; + this.age = age; + } + } + + let seho = new Person('세호', 30) // '생성 되었습니다' + console.log(seho); + + ``` + + +* 타입스크립트의 클래스 문법 + + ``` + // 기존 js에서 사용하는 클래스 문법과 다르게 멤버 변수를 정의해줘야 한다. + class Person { + private name: string; // private를 사용함으로써 클래스 내부에서만 사용할 변수임을 나타낸다. + (public, protected) public age: number; + readonly log: string; // leadonly 속성을 통해 log라는 변수는 접근만 할 수 있고 실제로 값은 변경할 수 없다는 것을 뜻한다. + + constructor(name: string, age: number) { + this.name = name; + this.age = age; + } + } + ``` diff --git "a/typescript/lecture/10.\354\240\234\353\204\244\353\246\255.md" "b/typescript/lecture/10.\354\240\234\353\204\244\353\246\255.md" new file mode 100644 index 0000000..fa1dbfc --- /dev/null +++ "b/typescript/lecture/10.\354\240\234\353\204\244\353\246\255.md" @@ -0,0 +1,205 @@ +* 제네릭 소개 + + - 마치 타입을 함수의 파라미터로 받는 것과 같다. + + - API 함수를 호출 후 API의 응답, 규칙을 정의할 때 많이 사용된다. + +* 제네릭의 기본 문법 + + ``` + function logText(text) { + console.log(text); + return text; + } + + logText(10); // 숫자 10 + logText('하이'); // 문자열 하이 + logText(true); // 진위값 true + + + + function logText(text: T): T { + console.log(text); + return text; + } + + logText(); // logText()에 마우스를 올려보면 함수의 스펙을 보여주는데, function logText(text: unknown): unknown 이라고 나온다. 이 말인 즉, logText()를 호출할 때 전달되는 인자의 타입을 같이 전달해주겠다는 것. + + logText('하이';) + + ``` + + +* 기존 타입 정의 방식과 제네릭의 차이점 - 함수 중복 선언의 단점 + + ``` + function logText(text: string) { + console.log(text); + return text; + } + + function logText(num: number) { + console.log(num); + return num; + } + + 위에와 아래는 동일한 로직의 코드인데, parameter로 받는 인자의 타입만 다르다. 파라미터 타입의 차이만 있는데, 위와 같이 함수를 나누는 것은 유지 보수에 있어 안좋다. + ``` + + +* 기존 문법과 제네릭의 차이점 - 유니온 타입을 이용한 선언 방식의 문제점 + + ``` + function logText(text: string | number) { // 전달인자로 string 혹은 number 타입, 두 타입을 모두 받을 수 있다. + 이런 경우 text. 으로 접근했을 때, string과 number 타입의 공집합인 즉, string, number에서 모두 사용될 수 있는 API들만 자동완성에 띄워진다는 문제점이 있다. + + } + + const a = logText('a'); // logText 함수의 return 되는 것의 타입이 어떤 것인지 몰라 제한적으로 사용될 수 밖에 없다는 단점이 있다. + ``` + + +* 제네릭의 장점과 타입 추론에서의 이점 + + ``` + function logtText(text: T): T { + console.log(text); + return text; + } + + const str = logText('abc') // logText를 호출할 때, string 타입을 사용하겠고 선언하는 것, logText()의 return 값이 string 타입이라는 것을 예측하고 string 관련 함수들을 자동 완성해준다. 또 함수를 호출할 때 타입을 집어넣을 수 있기에 위에서 마주했던 동일한 코드이지만, 함수의 전달인자 타입으로 인해 중복 코드를 작성해야 되는 부분을 없앨 수 있다. + ``` + +* 제네릭 실전 예제 살펴보기 - 예제 설명 + + + +* 제네릭 실전 예제 살펴보기 - 코드에 타입 정의하기 + + ``` + interface Email = { + value: string; + selected: boolean; + } + + //const emails: { value: string; selected: boolean }[] = [ + const emails: Email[] = [ + { value: 'naver.com', selected: true } + { value: 'gmail.com', selected: false } + { value: 'hanmail.net', selected: false } + ]; + + const ProductNumber = { + value: number; + selected: boolean; + } + + //const numberOfProducts: { value: number; selected: boolean }[] = [ + const numberOfProducts: ProductNumber[] = [ + { value: 1, selected: true } + { value: 2, selected: false } + { value: 3, selected: false } + ]; + + //function createDropdownItem(item: { value: string; selected: boolean}) { // 이때createDropdownItem()를 emails와 nuberOfProducts 로 모두 사용하는데, 함수의 전달인자 타입으로 value가 string 한가지 타입으로 고정되어 있어 두개의 변수를 못 담아내는 문제가 있다. 이럴 경우를 위해 제네릭을 붙인다. + function createDropdownItem(item: Email | ProductNumber) { // item에 대해 union type으로 설정한 경우, 그러나 또다른 타입의 변수를 담아내기 위해 그 타입의 interface를 만들고, 함수 전달인자에 유니언 타입으로 그 새로운 interface 타입을 추가해줘야 한다. 이런 모든 경우를 포괄할 수 있는 제네릭이 필요. + const option = document.createElement("option"); + option.value = item.value.toString(); + option.innerText = item.value.toString(); + option.selected = item.selected; + return option; + } + + emails.forEach(function (email) { + const item = createDropdownItem(email); + const selectTag = document.querySelector("#email-dropdown"); + selectTag.appendChild(item); + }); + ``` + +* 인터페이스에 제네릭을 선언하는 방법 + + ``` + interface Dropdown { + value: string; + selected: boolean; + } + + interface Dropdown { + value: T; + selected: boolean; + } + + const obj: Dropdown = { value: 'abc', selected: true }; + const obj: Dropdown = { value: 10, selected: false }; + + ``` + +* 제네릭 실전 예제 살펴보기 - 제네릭을 이용한 타입 정의 + + 제네릭이 적용된 하나의 interface를 사용하여, 여러 type을 구현할 수 있다. 제네릭의 장점, 타입 코드를 줄여나갈 수 있다. + + 제네릭이 적용된 interface를 통해 위 creatDropdownItem 함수에서 사용된 유니언 타입을 대체할 수 있다. + + +* 제네릭의 타입 제한 // 타입에 대한 힌트를 제공할 수 있다. + + ``` + function logTextLength (text: T): T { + console.log(text.length); // text는 T타입이여서 length가 없다는 에러를 뿜어낸다. + return text; + } + + logTextLength("abc"); // 위 console.log()에서 에러 발생, 문자열을 전달인자로 넣어줘서 text의 length가 접근이 가능할 거라 생각할 수 있지만, 타입스크립트에서는 어떤 타입으로 logTextLength()를 호출할지를 모르는 상황이다. + + 만약 변수의 .length를 사용하려한다면 제네릭 타입에 힌트를 줄 수 있다. + + function logTextLength (text: T[]) {// 와 같이 함수 전달인자로 T 배열이 들어올 것이라는 것을 예측할 수 있게끔 할 수 있다. + ... + } + ``` + + +* 정의된 타입으로 타입을 제한하기 + + ``` + interface LengthType { + length: number; + } + + function logTextLength (text: T) { + text.length; // text에 length 라는 속성이 있음을 T extends LengthType을 통해 알 수 있다. T 타입은 LengthType 내에 있는 모든 속성들을 가지고 있다는 것을 뜻한다. + // 그런데 이 부분에서 오해한 것이 logTextLength(10) 과 같이 함수를 호출해도 10이라는 number타입에 length가 있게 되는 줄 알았다. 왜냐면 logTextLength함수에 전달인자 타입은 LegnthType 인터페이스를 상속하기에. 그런데, 인터페이스를 상속한다는 것이 자동으로 상속한다는 게 아니라 저 인터페이스 타입을 상속해야만 한다는 것이였다.. 약간의 미묘한 의미 차이로, 이해가 됬다..! + } + + 해당 관련해서 올린 질문 내용: https://www.inflearn.com/questions/411248 + ``` + + +* keyof로 제네릭의 타입 제한하기 + + ``` + interface ShoppingItem { + name: string; + price: number; + stock: number; + } + + //function getShoppingItemOption (itemOption: T): T { + //return itemOption; + //} + + function getShoppingItemOption (itemOption: T): T { + return itemOption; + } + + getShoppingItemOption()을 호출할 때, 전달인자로 ShoppingItem 내의 속성 중 하나만, 혹은 ShoppingItem 내의 속성들로만 받게끔 하기위해 keyof 를 사용한다. 정확하게 말해서, ShoppingItem 내의 key만을 함수의 전달인자로 사용가능하게끔 하는 것이다. + + getShoppingItemOption('name'); + + ``` + + ![image](https://user-images.githubusercontent.com/53415000/150625802-dab49487-35d0-4e13-8447-504c07c6b7f8.png) + + 출처) https://joshua1988.github.io/ts/guide/generics.html#%EC%A0%9C%EB%84%A4%EB%A6%AD-%EC%A0%9C%EC%95%BD-%EC%A1%B0%EA%B1%B4 + diff --git "a/typescript/lecture/11.\354\240\204\355\231\224\353\262\210\355\230\270\353\266\200-\354\225\240\355\224\214\353\246\254\354\274\200\354\235\264\354\205\230.md" "b/typescript/lecture/11.\354\240\204\355\231\224\353\262\210\355\230\270\353\266\200-\354\225\240\355\224\214\353\246\254\354\274\200\354\235\264\354\205\230.md" new file mode 100644 index 0000000..c1d93ce --- /dev/null +++ "b/typescript/lecture/11.\354\240\204\355\231\224\353\262\210\355\230\270\353\266\200-\354\225\240\355\224\214\353\246\254\354\274\200\354\235\264\354\205\230.md" @@ -0,0 +1,35 @@ +``` + function fetchItems(): string[] { + let items = ['a', 'b', 'c']; + return items; + } + + let result = fetchItems(); + + 위와 같은 동기적인 코드에 있어 fetchItems()의 return 타입이 무엇인지 명시해주지 않아도 ts language server로 인해 return 타입이 string[] 임을 알 수 있다. + + + function fetchItems() { + let items = ['a', 'b', 'c']; + + return new Promise((resolve) => { + resolve(items); + }); + } + 그러나 비동기적인 코드를 실행 시 typescript는 Promise 안에 실행되는 것들에 대해 알지 못한다. 따라서 위의 경우 Promise이라는 값을 return 하고 있게 된다. + + 그래서 Promise 비동기 후 return 될 것이 무엇인지에 대해 명시적으로 작성해줘야 한다. + + function fetchItems(): Promise { // Promise는 기본적으로 generic 타입을 사용하고 있기에, generic 타입을 집어놓고 돌려받는 것을 뜻한다. Promise에서 resolve()로 넘기는 값의 타입이 반환 타입으로 설정되어야 한다. + //...; + } + + 동기적인 코드는 type 추론이 가능하지만, 비동기적인 코드는 type 추론이 불가하다. + + class의 constructor의 return 타입은 설정하지 않는다. + + 함수를 호출할 때, 전달인자로 정해진 범주의 string값을 넘기는 상황일 경우, 파라미터로 string값을 적을 때, 오탈자가 날 수 있다. 다시 말해 getNumberOfPlace()의 전달인자로 "home", "office", "studio"와 같은 경우만 전달인자로 넘길 수 있는데, 전달인자로 넘길 때, 오탈자를 넘길 수 있다. getNumberOfPlace("sdudio") 등과 같이. 따라서 이런 경우 타입 관점에서 안전한 코드를 작성하기 위해서, 직접 string 값이 적기보다는 이넘을 변수값을 넣도록 하는 것이 더 안전한 방법이다. + + + +``` diff --git "a/typescript/lecture/12.\355\203\200\354\236\205\354\266\224\353\241\240.md" "b/typescript/lecture/12.\355\203\200\354\236\205\354\266\224\353\241\240.md" new file mode 100644 index 0000000..d4109c6 --- /dev/null +++ "b/typescript/lecture/12.\355\203\200\354\236\205\354\266\224\353\241\240.md" @@ -0,0 +1,81 @@ +* 타입 추론(type inference) 소개 + + ``` + 타입 추론이란 + - 타이스크립트가 타입을 추론하는 것 + + 타입 추론을 해가는 과정 + - 변수를 선언하거나, 초기화할 때 타입이 추론된다. + - 변수, 속성, 인자의 기본 값, 함수의 반환 값 등을 설정할 때 타입이 추론된다. + + let a; // a는 any 타입, ts 파일 내부에서 language server가 돌아가서 변수의 타입을 추론한다. + + function getB(b = 10) { // b라는 값에 default로 10을 할당시킨다. 이때 b의 타입은 number 타입; + + return b; + } + ``` + + +* 인터페이스와 제네릭을 이용한 타입 추론 방식 + + ``` + //타입 추론 기본2 + interface Dropdown { + value: T; + title: string; + } + + let item: Dropdown = { // value의 타입은 string 타입임을 자동완성으로 띄워준다. + value: "abc", + title: "hello" + } + ``` + + +* 복잡한 구조에서의 타입 추론 방식 + + ``` + // 타입 추론 기본3 + interface Dropdown { + value: T; + title: string; + } + + interface DetailedDropdown extends Dropdown{ + description: string; + tag: K; + // extends로 value와 title 속성을 갖게 된다. + } + + let detailedItem: DetailedDropdown = { // DetailedDropdown에 제네릭 값에 string을 넘김 + title: "abc", + description: "ab", + value: "a", + title: "a", + } + ``` + + +* 가장 적절한 타입(Best Common Type) 추론 방식 + + ``` + - 타입은 보통 몇 개의 표현식(코드)을 바탕으로 타입을 추론. + - 그리고 표현식을 이용하여 가장 근접한 타입을 추론하는데 이 가장 근접한 타입을 'Best Common Type'이라고 한다. + + let arr = [1, 2, 3]; // arr은 number[]임을 나타낸다. + let arr = [1, 2, true]; arr은 (number | boolean)[] 타입임을 union 타입으로 구분해가며 나타낸다. + ``` + + +* Typescript Language Server 소개 + + ``` + intellisense - intelligent 하게 코드 완성 기능을 보여주는 것 + + intellisense가 작동되기 위해선, 내부적으로 typescript language server가 작동되어야 한다. + + LSP - Language Server Protocol + + language server 밑에서 돌아가기 때문에 type 추론이 가능하다. + ``` diff --git "a/typescript/lecture/13.\355\203\200\354\236\205\353\213\250\354\226\270.md" "b/typescript/lecture/13.\355\203\200\354\236\205\353\213\250\354\226\270.md" new file mode 100644 index 0000000..ee62413 --- /dev/null +++ "b/typescript/lecture/13.\355\203\200\354\236\205\353\213\250\354\226\270.md" @@ -0,0 +1,26 @@ +* 타입 단언(type-assertion) 소개 + + ``` + let a; // a의 타입은 any + //let b = 10; // b의 타입은 number; + //let b = a; // b의 타입은 any; + a = 20; + a = 'a'; + let b = a; // 이때 a의 타입은 any, typescript에서의 추론방식에서는 a에 값이 어떤 것이 들어갔는지에 따라 바로 추론하지는 못한다. 따라서 b의 타입도 any 타입 + let b = a as string; // 이때 b의 타입은 string 타입, 개발자가 typescript가 타입을 추론하는 것보다 type을 명확하게 아는 경우 type assertion을 한다. + + DOM API 할 때, type-assertion을 많이 사용한다. + + + ``` + + +* 타입 단언 예제 + + ``` + let div = document.querySelector('div'); // div 타입은 HTMLDivElement 혹은 null 이 될 수 있다. 만약 div 타입이 무조건(!) HTMLDivElement 일 수 밖에 없는 경우, as HTMLDivElement로 타입을 단언해준다. 만약 타입 단언을 했는데, 해당 타입이 단언한 타입과 다른 경우, 에러를 뿜는다. 따라서 좀 더 안전한 방식으로 코드를 작성할 때에는 타입 단언보다는 각각의 케이스에 대해서 예외를 처리해주는 것이 좋다고 한다.(cf, https://www.inflearn.com/questions/212653) + if (div) { // 특정 시점에 div 엘리먼트를 가져왔을 때, 존재하지 않을 수도 있기에 + div.innerText = "~~~" ; 위에서 div가 존재하는 조건을 걸어줬기에, div의 innerText에 접근 간으 + + } + ``` diff --git "a/typescript/lecture/14.\355\203\200\354\236\205\352\260\200\353\223\234.md" "b/typescript/lecture/14.\355\203\200\354\236\205\352\260\200\353\223\234.md" new file mode 100644 index 0000000..ad364b9 --- /dev/null +++ "b/typescript/lecture/14.\355\203\200\354\236\205\352\260\200\353\223\234.md" @@ -0,0 +1,54 @@ +* 타입 가드를 위한 예제 소개 + + ``` + interface Developer { + name: string; + skill: string; + } + + interface Person { + name: string; + age: number; + } + + function introduce(): Developer | Person { + return { name: 'Tony', age: 33, skill: 'Iron Making' } + } + + let tony = introduce(); + console.log(tony.skill); // 여기서 error 발생, 유니언 타입으로 여러 타입을 return해주는 경우, 공통된 속성에만 접근할 수 있기에 error 발생. + + if ((tony as Developer).skill) { // tony라는 변수의 타입은 Developer라고 단언하는 것 + console.log((tony as Developer).skill);// Developer의 skill을 찍어볼 수 있다. + } else if ((tony as Person).age) { + console.log((tony as Person).age); + } + + 타입 단언을 활용한 타입 정의를 통해 if와 else if 문 내에 조건을 걸어주고 있다. + 그런데 이와 같은 경우 중복되는 코드가 너무 많이 발생하여 가독성이 떨어지게 되는데, 이런 경우 타입 가드를 통해 해결할 수 있다. + + ``` + +* 타입 가드 소개와 적용 + + ``` + function isDeveloper(target: Developer | Person): target is Developer { // 타입가드 함수를 만들때 보통 'is해당타입' 과 같은 패턴을 활용한다. + // is 라는 keyword를 사용하여 전달인자가 Developer 타입인지를 구분한다. + + return (target as Developer).skill !== undefined; // target의 타입이 Developer이고 그 타입내 skill 속성이 undefined가 아닐 때, target은 developer 타입이라고 할 수 있다. 즉 전달인자로 넘긴 것의 타입이 Developer 타입인지 아닌지를 구분해줄 수 있다. + } + + 위 함수를 통해 기존에 구현했던 코드가 줄어든다. + + tony 변수는 위에서 introduce()를 통해 선언된 변수 + + if (isDeveloper(tony)) { + tony.skill; + } else { + tony.age; + } + + 타입 가드 같은 경우는 실제 많이 사용되기에 해당 패턴을 잘 익혀둘 것 + + + ``` diff --git "a/typescript/lecture/15.\355\203\200\354\236\205\355\230\270\355\231\230.md" "b/typescript/lecture/15.\355\203\200\354\236\205\355\230\270\355\231\230.md" new file mode 100644 index 0000000..49ba50c --- /dev/null +++ "b/typescript/lecture/15.\355\203\200\354\236\205\355\230\270\355\231\230.md" @@ -0,0 +1,105 @@ +* 타입 호환이란? + + ``` + 타입 호환(type compatibility): + - 타입스크립트 코드에서 특정 타입이 다른 타입에 잘 맞는지를 의미. + - 타입스크립트가 코드를 해석해나가는 과정에서 두 개의 타입이 서로 호환이 되는지를 점검하는 것 + + interface Ironman { + name: string; + } + + class Avengers { + name: string; + } + + let i: Ironman; + i = new Avengers(); + + > C#이나 Java였다면 위 코드에서 에러가 날겁니다. 왜냐하면 Avengers 클래스가 명시적으로 Ironman 인터페이스를 상속받아 구현하지 않았기 때문입니다. + + > 하지만 위와 같은 코드가 타입스크립트에서 정상적으로 동작하는 이유는 자바스크립트의 작동 방식과 관련이 있습니다. 기본적으로 자바스크립트는 객체 리터럴이나 익명 함수 등을 사용하기 때문에 명시적으로 타입을 지정하는 것보다는 코드의 구조 관점에서 타입을 지정하는 것이 더 잘 어울립니다. + + * 구조적 타이핑(structural typing)이란? + - 코드 구조 관점에서 타입이 서로 호환되는지의 여부를 판단하는 것 + + interface Avengers { + name: string + } + + + let hero: Avengers; + let capt = { name: "Captain", location: "Pangyo" }; + hero = capt; + + // capt가 hero 타입에 호환될 수 있는 이유는 capt의 속성 중 name이 있기 때문이다. Avengers 인터페이스에서 name 속성을 갖고 있기 때문에 capt는 Avengers 타입에 호환될 수 있다. + + ``` + + +* 타입 호환 예제 - 인터페이스, 클래스 + + ``` + interface Developer { + name: string; + skill: string; + } + + interface Person { + name: string; + } + + let developer: Developer; + let person: Person; + + developer = person; // error 발생, developer보다 person의 속성이 더 적기때문에, '=' 오른쪽에 있는 타입이 더 많은 속성을 갖고 있거나 구조적으로 컸을 때 타입 호환이 가능하다. + + person = developer; // error 발생하지 않는다. + + class Person { + name: string; + } + + developer = new Person() // error 발생 + ``` + +* 타입 호환 예제 - 함수, 제네릭 + + ``` + let add = function(a: number) { + //... + } + + let sum = function(a: number, b: number) { + //... + } + + add = sum; // error 발생 + sum = add; // error X + + + //제네릭 + interface Empty { + //... 비어 있는 경우 + } + + let empty1: Empty; + let empty2: Empty; + + empty1 = empty2; + empty2 = empty1; + // 위 두개의 식은 문제 없이 실행된다. + + interface NotEmpty { + data: T; + } + + let notEmpty1: NotEmpty; + let notEmpty2: NotEmpty; + + notEmpty1 = notEmpty2; // error 발생 + notEmpty2 = notEmpty1; // error 발생 + // 위 두개의 식은 error를 발생시킨다. + + + ``` diff --git "a/typescript/lecture/16.\355\203\200\354\236\205\353\252\250\353\223\210\355\231\224.md" "b/typescript/lecture/16.\355\203\200\354\236\205\353\252\250\353\223\210\355\231\224.md" new file mode 100644 index 0000000..5d79763 --- /dev/null +++ "b/typescript/lecture/16.\355\203\200\354\236\205\353\252\250\353\223\210\355\231\224.md" @@ -0,0 +1,29 @@ +* 타입스크립트의 모듈 시스템 + + ``` + interface Todo { + title: string; + checked: boolean; + } + + let item: Todo = { + title: '할일 1', + checked: false, + } + + 특정 타입을 여러 파일에서 사용할 경우, 하나의 파일에서 타입을 정리해 놓고 import export로 사용하면 좋다. + + js, ts 파일에서 import 하는 팁 - import {} from '경로'를 쓰면 {} 안에 경로에서 가져올 수 있는 것들에 대해 자동완성을 제공한다. + ``` + + +* 자바스크립트의 모듈 시스템 + + ``` + AMD(Asynchronous Module Definition), common JS와 같은 모듈 로더가 있다. 최신 js 문법에서 import와 Export로 표준화가 되었다. + ``` + +* 전화번호부 애플리케이션 모듈화 실습해보기 + + +* 전화번호부 애플리케이션 실습 풀이 diff --git "a/typescript/lecture/17.\352\263\240\352\270\211\355\203\200\354\236\205.md" "b/typescript/lecture/17.\352\263\240\352\270\211\355\203\200\354\236\205.md" new file mode 100644 index 0000000..973f2a6 --- /dev/null +++ "b/typescript/lecture/17.\352\263\240\352\270\211\355\203\200\354\236\205.md" @@ -0,0 +1,28 @@ +* 유틸리티 타입 + + - Advanced Type, 혹은 Generic Type이라고도 한다. + + - 이미 정의해 놓은 타입을 변환할 떄 사용하기 좋은 타입 문법 + + - 유틸리티 타입을 사용하지 않더라도, 인터페이스, 제네릭 등으로 타입을 변환할 수 있지만 이를 사용하면 훨씬 더 간결한 문법으로 타입 정의 가능 + + * Partial + + - 특정 타입의 부분 집합을 만족하는 타입을 정의 + + ``` + interface Address { + email: string; + address: string; + } + + type MayHaveEmail = Partial
; + const me: MayHaveEmail = {}; + const you: MayHaveEmail = { email: 'test@abc.com'}; + const all: MayHaveEmail = { email: 'dreams@come.true', address: 'RightNow'}; + + * Pick + + - + + ``` diff --git "a/typescript/11.\354\240\204\355\231\224\353\262\210\355\230\270\353\266\200-\354\225\240\355\224\214\353\246\254\354\274\200\354\235\264\354\205\230.md" "b/typescript/lecture/18.\353\247\265\353\223\234\355\203\200\354\236\205.md" similarity index 100% rename from "typescript/11.\354\240\204\355\231\224\353\262\210\355\230\270\353\266\200-\354\225\240\355\224\214\353\246\254\354\274\200\354\235\264\354\205\230.md" rename to "typescript/lecture/18.\353\247\265\353\223\234\355\203\200\354\236\205.md" diff --git a/typescript/lecture/readme.md b/typescript/lecture/readme.md new file mode 100644 index 0000000..22a6901 --- /dev/null +++ b/typescript/lecture/readme.md @@ -0,0 +1 @@ +* 캡틴 판교의 '타입 스크립트 입문'을 공부하는 내용을 정리하여 올립니다. diff --git a/typescript/notepad.md b/typescript/notepad.md new file mode 100644 index 0000000..37e722e --- /dev/null +++ b/typescript/notepad.md @@ -0,0 +1,340 @@ +### type과 interface의 차이 + + #### 확장(상속)하는 법 + + * interface + + * extends 키워드를 이용해서 확장할 수 있다. + + ``` + interface Person { + name: string; + age: number; + } + + interface Student extends Person { // 확장(상속) + school: string; + } + + const jieun: Student = { + name: 'jieun', + age: 27, + school: 'HY' + } + ``` + + * type + + * & 기호를 이용해서 확장할 수 있다. + + ``` + type Person = { + name: string, + age: number + } + + type Student = Person & { // 확장(상속) + school: string + } + + const jieun: Student = { + name: 'jieun', + age: 27, + school: 'HY' + } + ``` + #### 선언적 확장 + + * interface + + * 선언전 확장(Declaration Merging)이 가능하다. + (같은 이름의 interface를 선언하면, 자동으로 확장된다.) + + ``` + interface Person { + name: string; + age: number; + } + + interface Person { // 선언적 확장 + gender: string; + } + + const jieun: Person = { + name: 'jieun', + age: 27, + gender: 'female' + } + ``` + + * type + + * 선언적 확장이 불가능하다. + + ``` + type Person = { + name: string; + age: number; + } + + type Person = { // ❗️Error: Duplicate identifier 'Person'. + gender: string; + } + ``` + > => 따라서 타입 객체의 확장성을 위해서는 interface를 사용하는 것이 더 좋다. + + + ### 자료형(type) + + * interface + + * 객체(Object) 타입을 설정할 때 사용할 수 있으며, 원시 자료형에는 사용할 수 없다. + ``` + interface Person { + name: string; + age: number; + gender: string; + } + + interface name extends string { // ❌ 불가능 + ... + } + ``` + * type + + * 객체타이븡ㄹ 정희할 때도 사용할 수 있지만, 객체 타입을 정의할 때는 interface를 사용하는게 좋고, 단순한원시값(Primitive Type)이나 튜플(Tuple), 유니언(Union)타입을 선언할 때 type을 사용하는 것이 더 좋다. + + ``` + type Name = string; // primitive + type Age = number; + type Person = [string, number, boolean]; // tuple + type NumberString = string | number; // union + type Person = { // 객체는 interface를 사용하도록 하자. + name: string, + age: number, + gender: string + } + ``` + ### computed value 사용 + + * interface + + * computed value 사용이 불가능하다. + + ``` + type Subjects = 'math' | 'science' | 'sociology'; + + interface Grades { + [key in Subjects]: string; // ❗️Error: A mapped type may not declare properties or methods. + } + ``` + + * type + + * computed value 사용이 가능하다. + + ``` + type Subjects = 'Math' | 'Science' | 'Sociology'; + + type Grades = { + [key in Subjects]: string; + } + ``` + > 결론 + > + > type은 모든 타입을 선언할 때 사용할 수 있고, interface는 객체에 대한 타입 을 선언할 때만 사용할 수 있다. + > 또한 확장 불가능한 타입을 선언하고 싶다면 type을 사용하면 되고, 확장 가능한 타입을 선언하고 싶다면 interface를 사용하면 된다. + + +* type 호환 + + ``` + let primitiveStr: string; + primitiveStr = 'hello'; // OK + primitiveStr = new String("hello"); // Error, /** Type 'String' is not assinable to type 'string'. \n 'string' is a primitive, but 'String' is a wrapper object. Prefer using 'string' when possible. */ + + let objectStr: String; + objectStr = 'hello'; // OK + objectStr = new String('hello'); // OK + ``` + +* javascript + + - 동적 타입(dynamic typed), 느슨한 타입(loosely typed) 언어 + + - 변수의 타입 선언 없이 값이 할당되는 과정에서 동적으로 타입을 추론(Type Inference)한다는 의미 + + - 동적 타입 언어는 타입 춘론에 의해 변수의 타입이 결정된 후에도 같은 변수에 여러 타입의 값을 교차하여 할당 가능 + + ``` + var foo; + console.log(typeof foo); // undefined + + + foo = null; + console.log(typeof foo); // object + + ``` + +* 타입 추론 + + - 타입 선언을 생략하면 값이 할당되는 과정에서 동적으로 타입이 결정된다. 이를 타입 추론이라고 한다. + + +* 타입 캐스팅 + + - 기존의 타입에서 다른 타입으로 타입 캐스팅하려면 as 키워드를 사용하거나 <> 연산자를 사용할 수 있다. + + + ``` + const $input = document.querySelector('input[type="text"]'); // input: Element | null + + const val = $input.value; // Error, 'Element' 타입에 value라는 property가 없기 때문에. + + + => 아래와 같이 변경 + + 1. const $input = document.querySelector('input[type="text"]') as HTMLInputElement; + + OR + + const $input = document.querySelector('input[type="text"]'); + ``` + + + * 클래스 + + - ES6 클래스는 클래스 몸체에 '메소드'만을 포함할 수 있다. 클래스 몸체에 프로퍼티를 선언할 수 없고, 반드시 생성자 내부에서 클래스 프로퍼티를 선언하고 초기화한다. + + - typescript 클래스는 클래스 몸체에 클래스 프로퍼티를 사전 선언해야 한다. + + - typescript의 클래스는 접근 제한자를 명시하지 않았을 때, 다른 클래스 기반 언어의 경우, 암묵적을 protected로 지정되어 패키지 레벨로 공개되지만, typescript의 경우, 접근 제한자를 생략한 클래스 프로퍼티와 메소드는 암묵적으로 public을 선언됨. + + - 접근 제한자는 생성자 파라미터에도 선언 가능. 접근 제한자가 사용된 생성자 파라미터는 암묵적으로 클래스 프로퍼티로 선언되고 생성자 내부에서 별도의 초기화 없어도 암묵적으로 초기화가 수행된다. private 접근 제한자가 사용되면 클래스 내부에서만 참조 가능하고 public 접근 제한자가 사용되면 클래스 외부에서도 참조가 가능하다. + + - readonly가 선언된 클래스 프로퍼티는 선언 시 또는 생성자 내부에서만 값을 할당할 수 있다. + + + * static + + - 정적 메서드(static method)는 클래스의 인스턴스가 아닌 클래스 이름으로 호출한다. 따라서 클래스의 인스턴스를 생성하지 않아도 호출할 수 있다. + + - 정적 메서는 this를 사용할 수 없다. 정적 메서드 내부에서 this는 클래스의 인스턴스가 아닌 클래스 자신을 가리킨다. + + - 정적 메서는 인스턴스로 호출할 수 없다. + + - static 키워드를 클래스 프로퍼티에도 사용할 수 있다. 정적 메서드와 마찬가지로 정적 클래스 프로퍼티는 인스턴스가 아닌 클래스 이름으로 호출하며 클래스의 인스턴스를 생성하지 않아도 호출할 수 있다. + + + * 덕 타이핑(Duck typing) + + - 인터페이스를 구현하였다는 것만이 타입 체크를 통과하는 유일한 방법은 아니다. 타입 체크에서 중요한 것은 값을 실제로 가지고 있는 것이다. + + ``` + interface IDuck { // 1 + quack(): void; + } + + class MallardDuck implements IDuck { // 3 + quack() { + console.log('Quack!'); + } + } + + class RedheadDuck { // 4 + quack() { + console.log('q~uack!'); + } + } + + function makeNoise(duck: IDuck): void { // 2 + duck.quack(); + } + + makeNoise(new MallardDuck()); // Quack! + makeNoise(new RedheadDuck()); // q~uack! // 5 + + + /** + * typescript는 해당 인터페이스에서 정의한 프로퍼티나 메서드를 가지고 있다면 그 인터페이스를 구현한 것으로 인정한다. 이를 "덕 타이핑(duck typing) 또는 구조적 타이핑(structural typing)"이라 한다. + */ + + interface IPerson { + name: string; + } + + function sayHello(person) { + console.log("Hello " + person.name); + } + + var me = { name: 'Lee', age: 18 }; + sayHello(me); // Hello Lee + + // 변수 me는 인터페이스 IPerson과 일치하지 않는다. 하지만 IPerson의 name 프로퍼티를 가지고 있으면 인터페이스에 부합하는 것으로 인정된다. 인터페이스는 개발 단계에서 도움을 주기 위해 제공되는 기능일 뿐 JS의 표준은 아님. 따라서 위 예제의 typescript 파일을 js파일로 트랜스파일링하면 아래와 같이 인터페이스가 삭제된다. + + function sayHello(person) { + console.log("Hello " + person.name); + } + + var me = { name: 'Lee', age: 18 }; + sayHello(me); // Hello Lee + ``` + + - 선택적 프로퍼티 + + - 인터페이스의 프로퍼티는 반드시 구현되어야 한다. + + - 만약 프로퍼티명 뒤에 ?를 붙이면 '선택적 프로퍼티(Optional Property)'로 해당 프로퍼티를 생략하여도 에러가 발생하지 않는다. + + - 인터페이스는 extends 키워드를 사용하여 인터페이스 혹은 클래스를 상속받을 수 있다. (복수개의 인터페이스를 상속 받을 수도 있다. + + ``` + interface IPerson { + name: string; + age?: number; + } + + interface IDeveloper { + skills: string[]; + } + + interface IWebDeveloper extends IPerson, IDeveloper {} + + const webDeveloper: IWebDeveloper = { + name: "Lee", + age: 20, + skills: ['HTML' ,'CSS', 'JavaScript'] + } + ``` + + - 인터페페이스는 클래스를 상속받을 수 있는데, 클래스의 모든 멤버(public, protected, private)가 상속되지만 구현까지 상속하지는 않는다. + + + * 타입 앨리어스 + + - 타입 앨리어스는 새로운 타입을 정의 + + - 타입으로 사용한다는 점에서 인터페이스와 유사 + + - 인터페이스와는 다르게 타입 앨리어스는 원시값, 유니온 타입, 튜플 등도 타입으로 지정할 수 있다. + + ``` + type Str = "Lee"; // 문자열 리터럴로 타입 지정 + + type Union = string | null; // 유니온 타입으로 타입 지정 + + type Name = 'Lee' | 'Kim'; // 문자열 유니온 타입으로 타입 지정 + + type Func = (() => string) | (() => void); // 함수 유니온 타입으로 타입 지정 + + type Shape = Square | Rectangle | Circle; // 인터페이스 유니온 타입으로 타입 지정 + + type Tuple = [string, boolean]; // 튜플로 타입 지정 + const t: Tuple = ["", ""]; // error + ``` + + - 인터페이스는 extends 혹, implements 할 수 있지만 타입 앨리어스는 불가 + + - 상속을 통해 확장이 필요하다면 인터페이스 + + - 인터페이스로 표현할 수 없거나 유니온 또는 튜플을 사용해야 한다면 타입 앨리어스를 사용하는 편이 유리 diff --git a/typescript/package-lock.json b/typescript/package-lock.json new file mode 100644 index 0000000..fd70da1 --- /dev/null +++ b/typescript/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "typescript", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "typescript": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", + "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==" + } + } +} diff --git a/typescript/package.json b/typescript/package.json new file mode 100644 index 0000000..c9d0bc8 --- /dev/null +++ b/typescript/package.json @@ -0,0 +1,15 @@ +{ + "name": "typescript", + "version": "1.0.0", + "description": "* 캡틴 판교의 '타입 스크립트 입문'을 공부하는 내용을 정리하여 올립니다.", + "main": "index.js", + "dependencies": { + "typescript": "^4.5.5" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git "a/typescript/quick-start/01.\354\206\214\352\260\234.md" "b/typescript/quick-start/01.\354\206\214\352\260\234.md" new file mode 100644 index 0000000..a05fb7c --- /dev/null +++ "b/typescript/quick-start/01.\354\206\214\352\260\234.md" @@ -0,0 +1,149 @@ +## 소개 + + * CommonJS 방식 / AMD(asynchronouse Module Definition) 방식 + + - CommonJS 방식: import, export 키워드를 이용해 모듈을 노출하거나 불러온다. / Node.js가 채택한 방식 + + - AMD 방식: 모듈 로더에 의해 런타임 시에 모듈을 비동기로 호출할 수 있다. + + + * 대규모 애플리케이션을 개발하는 데 필요한 조건 + + - 모듈화 기능을 통해 모듈 간의 결합도(coupling)을 줄일 수 있어야 한다. + + -> 모듈 시스템 - ES6 모듈과 네임스페이스 지원 + + - 객체지향 프로그래밍을 지원해 코드의 중복과 복잡도를 낮출 수 있어야 한다. + + -> 클래스와 인터페이스 지원 + + - 코드 규모가 커지더라도 구조화를 갖춰 개발할 수 있어야 한다. + + -> 타입 시스템 지원 + + + * 타입스크립트의 모듈 시스템 + + - 크게 ES6 모듈과 네임스페이스로 나뉜다. + + * ES6 모듈 + + - 기존 ES5에서 어려웠던 모듈 분할과 결합 기능을 향상시킴 + + * 네임스페이스 + + - ES6에 없는 타입스크립트에 추가된 것으로, 분리된 이름 공간을 제공해 복잡도를 낮춘다. + + cf) 네임스페이스가 지원되기 전 자바스크립트에서는 네임스페이스 패턴을 이용해 분리된 이름 영역을 관리해야하는 불편함이 있었다. + + - 클래스가 커지고 갯수가 많아지면 유사한 기능의 클래스들을 그룹으로 구분 지을 필요가 생기는데, 이러한 영역 구분에 네임스페이스 같은 기능을 도입하면 된다. + + - 라이브러리 단위의 모듈 구성에 유리 + + - 규모 있는 모듈 구성에 필요한 특징 + + - 전역 이름 공간(global namespace)과 구분된 별도의 이름 영역을 가지므로 전역 이름 공간의 오염을 막는다. + + - 각 네임스페이스에서는 인터페이스, 클래스, 함수 등의 모듈을 선언할 수 있음 + + - 네임스페이스 간에는 이름 영역이 다르므로 같은 이름의 모듈을 각각의 네임스페이스에서 선언할 수 있다. + + + * 클래스와 인터페이스 + + - 타입스크립트는 ES6에 없는 인터페이스 선언과 구현을 지원한다. + + - 자바는 다중 생성자를 선언할 수 있지만, 타입스크립트는 단일 생성자만 선언할 수 있다. + + + * 타입 어노테이션(type annotation) + + - 타입 어노테이션을 이용해 변수에 타입을 선언할 수 있다. + + - 타입스크립트에서 변수나 함수의 매개변수 등에 선언한 타입 어노테이션은 컴파일할 때 타입 검사를 위한 목적으로 사용된다. + + - 타입 검사를 통해 타입 안전성이 확보되면 타입스크립트 컴파일러가 타입 어노테이션을 제거하고 최종적으로 자바스크립트 코드를 생성한다. + + - tsc 명령어를 이용해 타입스크립트 컴파일러를 실행한다. + + - 순수 js에서는 type에 대한 체크를 if 문을 통해 하는데, 이러한 if문이 많아질 수록 성능에 영향을 미친다. 타입 검사가 많아질 수록 런타임 오버헤드(runtime overhead)가 발생할 수 있다. 따라서 타입스크립트는 이러한 불필요한 타입 검사를 하지 않게 되어 코드양을 줄이고, 성능 저하도 줄일 수 있다. + + + * Non-Nullable 타입 + + - undefined나 null 을 제외한 타입을 허용하는 타입 + + - tsconfig.json 설정에 strictNullChecks를 true로 지정하면 변수에 null이나 undefined를 곧바로 할당할 수 없게 된다. + + + * 타입 스크립트 정의 파일 + + - 타입스크립트 1.x에서 2.x로 버젼이 업데이트 되면서 서드파티 라이브러리의 타입 정의 파일을 도입하는 과정이 바뀌었다. + + - 타입스크립트 정의 파일은 자바스크립트가 타입스크립트의 모듈로 사용될 때 자바스크립트에 타입을 추가하는 역할을 한다. + + - 이 파일의 확장자는 .d.ts이며, 1.x 버젼의 타입스크립트에서 서드파티 라이브러리를 호출하려면 아래와 같은 방식으로 .d.ts 파일을 가져와야 했다. + + ``` + npm install -g typings + + typings install -gloabl lodash + + tsconfig.json 수정 + ``` + + - 2.x 버젼의 타입스크립트는 위와 같은 복잡한 절차를 거치지 않고, 아래와 같이 서드파티 라이브러리를 손쉽게 사용하게 되었다. + + ``` + npm install --save @types/lodash + ``` + + - js 라이브러리, 프레임워크 또는 외부 패키지의 타입 정보를 포함하는 파일.(일반적으로 .d.ts 확장자를 가지고 있음) + + - 정의 파일은 타입스크립트 컴파일러에 의해 사용되어 Javascript 코드와 상호 작용할 때 정적 타입 검사를 가능하게 합니다. 일반적으로 자바스크립트 라이브러리는 동적 타입 언어이기 때문에 타입 정보가 없거나 부족합니다. 그러나 타입스크립트는 정적 타입 언어이므로 변수, 함수, 클래스 등의 타입 정보가 필요합니다. 이를 위해 정의 파일을 사용하여 자바스크립트 코드에 대한 타입 정보를 제공한다. + + - 정의 파일은 주로 다음과 같은 정보를 포함할 수 있다. + + - 타입 선언: 변수, 매개변수, 반환 값 등의 타입 정보를 선언 + + - 인터페이스와 타입 별칭: 객체의 구조를 정의하거나 복잡한 타입을 정의하는데 사용 + + - 네임스페이스: 이름 공간을 정의하여 충돌을 방지하고 모듈화를 지원 + + - 모듈과 외부 모듈: 타입스크립트 모듈 시스템을 사용하는 경우, 모듈의 내용과 외부 모듈에 대한 타입 정로를 포함 + + - 정의 파일은 타입스크립트 개발 환경에서 주로 사용되며, 타입스크립트 컴파일러는 이 파일을 사용하여 타입 검사 및 코드 완성 기능을 제공 + + - 타입스크립트에서는 정의 파일이 없더라도 javascript 라이브러리를 사용할 수 있지만, 정의 파일을 사용하면 개발자들이 더욱 정확하고 안전한 코드를 작성할 수 있음. + + ``` + 다음은 예시 코드입니다. + + 라이브러리 이름: example-library + + example-library.d.ts (정의 파일) + + declare module "example-library" { + export function greet(name: string): void; + export interface Person { + name: string; + age: number; + } + } + + + // app.ts + import { greet, Person } from "example-library"; + + greet("John"); + + const person: Person = { + name: "Alice", + age: 25, + }; + + console.log(person); + + ``` + + diff --git a/typescript/readme.md b/typescript/readme.md index 22a6901..36c1df3 100644 --- a/typescript/readme.md +++ b/typescript/readme.md @@ -1 +1,20 @@ -* 캡틴 판교의 '타입 스크립트 입문'을 공부하는 내용을 정리하여 올립니다. +## Typescript + +#### 유틸리티 타입 + +- 이미 정의되어 있는 타입 구조를 변경하여 재사용하고 싶을 때 사용하는 타입 + +- 미리 정의해 놓은 내장 타입이기 때문에 타입스크립트를 설치한 후 설정파일(tsconfig.json)의 lib 속성에 'ESNext'를 추가한뒤 사용하면 된다. + +- Pick, Omit 등과 같은 것들이 있다. + +#### Pick + +- 특정 속성을 뽑아서 새로운 타입을 만들어 낼 떄 사용한다. + + +#### Omit + +- 특정 타입에서 속성 몇개를 제외한 나머지 속성으로 새로운 타입을 생성할 때 사용하는 타입. + +- Pick과는 달리 특정 타입에서 속성 몇개만 제외하고 나머지 타입으로 새로운 타입을 생성한다. diff --git a/typescript/utility-type.ts b/typescript/utility-type.ts new file mode 100644 index 0000000..067c811 --- /dev/null +++ b/typescript/utility-type.ts @@ -0,0 +1,28 @@ +interface Product { + id: number; + name: string; + price: number; + brand: string; + stock: number; +} + + +function fetchProducts(): Promise { + +} + + +type ShoppingItem = Pick; + +// 간혹 Product의 detail 화면을 띄울 때, 위 인터페이스에 선언된 속성들 중 일부만을 출력할 수도 있다. +function displayProductDetail(shoppingItem: Pick) { + +} + +/** Omit 타입 */ +// Pick과는 정반대로 Product 타입에서 id와 name을 생략한 다른 속성들은 사용하겠다는 것. +const AmbigousProduct: Omit = { + price: 3000, + brand: "no-brand", + stock: 150 +}; \ No newline at end of file diff --git a/vue/notepad.md b/vue/notepad.md index 630cc3b..07a93db 100644 --- a/vue/notepad.md +++ b/vue/notepad.md @@ -1,5 +1,39 @@ **vue project 하며 겪는 실수들을 올립니다.** + - onMounted 내에서 async 함수를 사용해서 element를 못가져와 생긴 일 + + onMounted() 내에서 popup 리스트를 가져오는 함수를 async-await를 이용해 가져오게 됬다. 정확하게는 popup 리스트 가져오는 함수 내에서 store index.js의 actions 내에 있는 함수를 await store.dispatch("팝업 리스트 가져오는 함수명") 사용하였고 이후그 함수(popup 리스트를 가져오는 함수) 내부에서 html 돔을 가져와 쿠키에 설정된 정보를 바탕으로 popup을 띄우지 않도록 작업하였다. 그런데 html 돔을 가져오지 못하는 현상이 있었는데, 이유는 async 함수 내에서 돔을 조작하였기 때문이다. 따라서 async 함수 내에서 dom을 접근하는 것이 아니라, async-await 함수 내에서 로직 처리가 끝난 후 .then으로 dom을 접근할 수 있다. + + - Extraneous non-props attributes were passed to component but could not be automatically inherited 라는 warning 상황 + + 해당 warning은 vue 파일에 단일 루트 엘리먼트가 아닌 multi root element로 구성되어 있어 발생하였다. + + ``` + + + 와 같이 template 밑에 복수 개의 root element가 존재하기에 발생한다. + + 그런데 vue3에서 부터는 multi root element를 지원한다고 했는데, 왜 이런 warning이 발생하는지는 찾아봐야 겠다. + ``` + + - vuex + + 분명히 회사에서는 vuex의 useStore()를 활용하여 store를 불러와 사용했는데, 내가 진행했던 프로젝트에서는 useStore()를 불러오지 못하는 상황.. + + vuex 라이브러리를 설치하고 동일한 환경 세팅을 했는데, 작동이 되지 않아, vuex의 버전을 확인해보았다. 'npm i vuex'로 설치한 경우 version이 3.x 가 설치되었지만, 회사에서는 4.X를 사용하고 있었다. + + npm uninstall vuex로 삭제 후 npm i vuex@4.0.0으로 특정 버젼을 설치한 결과, 정상 작동하였다. + + - pinia: vuex 대용으로 사용되고 있는 vue 상태관리 라이브러리(참조: https://www.youtube.com/watch?v=LfWpPRId5N0) + + - pinia(피냐)의 경우, multiple data store가 존재하는 반면, vuex에서는 하나의 store만 존재. vuex submodule들이 존재하였지만, 이것들은 하나의 store를 사용하였지만, 피냐의 경우에는 각각의 submodule들이 store를 가질 수 있다고 한다. 따라서 컴포넌트 별로 필요한 store를 세분화해서 가져오는 code spliting이 가능하며, typescript 적용에 더 용이하다고 한다. + + - vuex에서는 state / mutations / actions / getters 이렇게 총 4개가 존재한 반면, pinia에서는 mutations를 제외한 3개만 존재한다고 한다. + + - vue 개발자 도구에서 vue 탭이 활성화 되지 않는 문제 - chrome에서 제공하는 vue-extension을 설치했지만, 개발자 도구에서 vue 탭이 활성화 되지 않았다.. (vue 탭으로 컴포넌트 관계를 명확하게 파악해서, 어디에서 문제가 있는지 확인하고 싶었는데..) 그래서 그 이유를 검색하다 보니, vue 프로젝트를 생성할 때, vue3 이상으로 생성하면 vue 탭이 활성화되지 않는다고 한다. diff --git a/vue/vue-ga[google-analytics].md b/vue/vue-ga[google-analytics].md new file mode 100644 index 0000000..6c073a4 --- /dev/null +++ b/vue/vue-ga[google-analytics].md @@ -0,0 +1,74 @@ +* Vue에 GA(Google Analytics) + + 프로젝트에 Google Analytics를 붙이라고 하시고, 참고하라는 사이트(https://velog.io/@bluestragglr/Vue.js%EC%97%90-Google-Analytics-%EB%B6%99%EC%9D%B4%EA%B8%B0) 까지 친절하게 알려주셔서 해당 작업을 하게 되었다. + + 작업을 하며 사이트에서는 vue-analytics라는 라이브러리를 사용하여 GA version 3를 붙여놓았지만, vue-analytics 라이브러리를 통해 현재 사용되는 GA 4에서 사용하는 'G-XXXXXX'라는 특성을 할 수없다고 나와 있었으며, 추후 포스팅을 한다고 하여 GA 4를 지원하는 vue 라이브러리를 다시 서칭하게 되었다. + + 서칭을 하며 GA 4를 지원하는 vue-gtag 라이브러리를 확인하여 이 라이브러리를 사용하게 되었다. vue-analytics와 vue-gtag를 사용하는 방법은 크게 달라진 점은 없었고(아래 코드1,2 참고), 단지 Google Analytics 4 속성으로 추가된 'G-XXXXXX' 속성 사용 유무만 있었다.(GA 4에서는 기존의 GA Universal Application('UA-xxxxxx')속성도 사용할 수 있었다.) + + ``` + 코드1 + // src/main.js + + import VueAnalytics from "vue-analytics"; + + Vue.use(VueAnalytics, { + id: 'UA-XXXXXX', + router // 원활한 트래킹을 위해서는 router를 반드시 바인딩 해야한다고 한다. + }); + ``` + + ``` + 코드2 + // src/main.js + + import VueGtag from "vue-gtag"; + + Vue.use(VueGtag, { + config: { id: G-XXXXXX } + }); + ``` + + 그런데,, 위 작업을 프로젝트에 붙여도 계속해서 발생하는 오류로 인해, 프로젝트를 vue가 아닌 vite으로 구성했다는 생각을 하게 됬고, 이 vite에서 지원하는 라이브러리인 vite-plugin-radar를 사용하게 되었다. + + 이 라이브러리는 위 라이브러리들과는 다르게 main.js에서 라이브러리를 추가하지 않고, vite.config.js 파일에서 plugin 속성에 등록한 후 사용할 수 있었다. + + ``` + // vite.config.js + + import { defineConfig } from "vite"; + import vue from "@vitejs/plugin-vue"; + + export default defineConfig({ + css: { + preprocessorOptions: { + scss: { + }, + }, + }, + plugins: [vue(), ViteRadar({ analytics: { id: "G-XXXXXX" } })], + build: { + rollupOptions: { + plugins: [], + }, + }, + }); + ``` + + 그리고 프로젝트에 GA가 붙여졌는지 확인하기 위해서는 위 사이트에서 말한 방법으로 확인할 수 있는데 크롬 extension( https://chrome.google.com/webstore/detail/tag-assistant-legacy-by-g/kejbdjndbnbjgmefkgdddjlbokphdefk?hl=ko )를 추가하여 확인할 수 있다. + +
+ 몇일이 지나고.. + + 프로젝트에 붙인 ga에 뭐 좀 봐달라고 하시는 호출이 왔다. 문제의 상황은 아래와 같다. + + ![image](https://user-images.githubusercontent.com/53415000/147733565-45d01c0f-b313-42c9-bd81-7a7dba6d105b.png) + + + 위 사진을 받고 검색해본 결과 대체로 두가지의 답변이 대다수였다. + + 1) 크롬 광고 차단(AdBlock) 확장 프로그램이 설치되었을 경우, 해당 확장 프로그램에서 GA를 막는 경우가 있다고 하여 광고 차단 확장 프로그램을 종료하는 방법 + + 2) gtag.js 설정 파일에서 transport_url이'https://www.example.com/g/collect' or 'https://www.example.com'이 맞는지 확인 + + 당면한 상황도 1번을 확인함으로써, 해결할 수 있었다. diff --git a/web/WebAssembly.md b/web/WebAssembly.md new file mode 100644 index 0000000..b522813 --- /dev/null +++ b/web/WebAssembly.md @@ -0,0 +1,33 @@ +

[WA 소개]

+ +* 웹은 원래 HTML, CSS, JS만 해석. But 17년 부터 WebAssembly도 해석(실행) 가능 + +* WA(WebAssembly)는 언어가 아닌, 브라우저에서 실행 가능한 새로운 파일 형식(.wasm) + +* 평소에 쓰던 프로그랭 언어들을 .wasm 형식으로 컴파일이 가능하다. 브라우저에서는 이 .wasm 파일을 실행한다. + +
+장점 + + * 다른 언어로 작성한 프로그램도 브라우저에서 실행가능(확장성)
+ * 작동속도가 빠르다. + +

+ +[브라우저가 js파일 실행할 때의 과정]
+javascript 파일 -> 간단한 parsing -> Bytecode로 변환(Bytecode란 기계친화적인 자바스크립트 번역본) -> 실행(interpreter가 Bytecode를 실행, 인터프리터를 "ingintion" 이라고 부른다.) + +
+ 반복되는 코드는 최적화를 진행( Optimizer가 Optimizing을 진행한다. 기계어랑 가까운 언어로 번역). 이후 Optimizing 된 코드는 크롬 내 Turbofan이라는 것이 실행시킨다. 이로 인해 js 파일을 빠르게 실행시킨다. + +그런데 optimzing된 코드를 취소해야 하는 경우가 생긴다, 가령 변수의 타입이 바뀐다거나 함수에 들어가는 전달인자의 타입, 갯수 등 변경 되는 경우가 생긴다. 그러면 optimizing 취소 작업을 하고 turbofan이 꺼지며, 다시 bytecode가 실행이 된다. + +
+ +[wasm 파일 실행 과정]
+크롬에서 liftoff라고 불리는 것이 wasm 파일을 실행시킨다. 컴파일된 파일을 브라우저에서 실행하기에 브라우저에서 js를 실행할 때 파싱되고 bytecode로 변환되는 과정이 없이 작동된다. 따라서 실행시작 속도가 매우 빠르다. 그리고 turbofan이 optimizing을 해주는데 js 파일 실행 때와는 다르게 .wasm 파일은 거의 대부분의 코드를 opitmizing 할 수 있다. 그리고 optimizing 취소가 거의 없다. 따라서 안정적으로 빠른 속도를 기대할 수 있다. 그렇지만 무조건 .wasm 파일이 .js 파일보다 빠르게 실행되는 것은 아니다. + +
+wasm은 js의 대체재가 아닌, js 내 특정 코드 부분 실행이 느린 경우, 그 부분을 wasm 파일로 대체할 수 있다. +카카오의 경우 대용량의 이미지의 보정 작업을 하는 경우, wasm을 통해 진행하면 절반 이상의 속도를 줄였다고 한다. +assemblyscript를 통해 wasm 파일을 만들어낼 수 있다. diff --git a/web/cors.md b/web/cors.md new file mode 100644 index 0000000..6c6d702 --- /dev/null +++ b/web/cors.md @@ -0,0 +1,38 @@ +[ CORS ] - Cross Origin Resource Sharing +https://www.youtube.com/watch?v=bW31xiNB8Nc 내용 6분 30초까지 정리 +https://www.youtube.com/watch?v=-2TgkKYmJt4 내용 12분까지 정리 + +한 사이트에서 주소가 다른 서버로 요청을 보낼 때 발생하는 문제. + +상황에 따라 http 요청을 보낼 때 정상 작동하는 곳이 있기도 한데, 정상 작동하지 않는 곳도 있다. 어디에서 보내는 요청이 막히는 것인지 알아야 한다. + +웹사이트에서 ajax 요청을 보낼 때마다 작동이 안되는데, 웹사이트를 여는 곳 즉, 크롬, 엣지, 사파리 같은 브라우저에서 일어나는 문제이다. 다시 말해 프론트엔드에서 일어나는 문제. +브라우저에서 내가 작업하는 곳에 요청을 보내지 못하도록 하는 것. + +* CORS 존재이유 + - 내 브라우저에서 다른 사이트로 요청이 못가는 것을 풀어주는 것 + - Cross-Origin으로 Same-Origin과는 반대의 말 + - 다른 출처 간에 리소스를 공유할 수 있도록 하는 것이다. + +SOP(Same-Origin Policy, 동일 출저 정책) +- 다른 출처(Origin)의 리소스를 사용하는 것에 제한하는 보안 방식 +cf) 출처란? 이미지 참고 +- 어떤 사이트에서 다른 사이트로 요청이 못가게끔 하는 것 +- 동일한 출처, URL 끼리만 API 등의 데이터 접근이 가능하도록 하고 다른 URL에 경우는 막는다. +- 상호간 document에도 극히 제한적으로 접근하게 된다. + +어떤 기준을 충족시키면 합의된 출처들 간에 합법적으로 자원(리소스) 공유를 허용해주는 것이 CORS, 교차 출처 자원 공유 방식이다. +그 기준은 요청을 받는 백엔드쪽에서 허락할 다른 출처들을 미리 명시해주면 된다. + +CORS 접근제어 시나리오 +- 단순 요청(Simple Request) +- 프리플라이트 요청(Preflight Request) +- 인증정보 포함 요청(Credentialed Request) + + * 프리플라이트 요청 + - 사전 확인 작업(본 요청을 보내기 전에 서버에게 요청을 보내도 되는지에 대해 물어보는 것) + - OPTIONS 메서드를 통해 다른 도메인의 리소스에 요청이 가능한 지 확인 작업을 한다. + - 요청이 가능하다면 실제 요청(Actual Request)을 보낸다. + - preflight 요청이 거부되면 actual request는 전송되지 않는다. + + * Simple Request diff --git a/web/csr-ssr.md b/web/csr-ssr.md new file mode 100644 index 0000000..29c1d9e --- /dev/null +++ b/web/csr-ssr.md @@ -0,0 +1,40 @@ +본 글은 드림 코딩 엘리의 강의를 정리한 글입니다. + +cf) https://www.youtube.com/watch?v=iZ9csAfU5Os&t=140s + + +[ 역사로 알아보는 csr과 ssr ] +1990 중반 까지 - static sites ( 서버 내에 이미 배포되어 있는 html 문서를 받아와서 화면에 보여주는 형식) + but 문제: 페이지 내 다른 링크 클릭 시 서버에서 다시 해당 html 문서를 받아와 페이지 전체가 업데이트 되는 문제. + +1996 - 문서 내에서 또 다른 문서를 담을 수 있는 iframe 태그가 도입됨에 따라 페이지 내에서 부분적으로 문서를 받아와서 업데이트를 할 수 있게 되었다. + +1998 이후 - XMLHttpRequest(fetch API의 원조)로 html 문서 전체가 아닌, json과 같은 포맷으로 서버에서 가볍게 필요한 데이터만 받아올 수 있게 되었다. 이 데이터를 javascript를 사용해 동적으로 html 요소를 생성해 업데이트 할 수 있게 되었다. + +2005 - 위와 같은 방식이 공식적으로 'AJAX'라는 이름을 갖게 됨, 이것이 SPA(Single Page Application). 사용자가 페이지 내에 머무르면서 필요한 데이터를 서버에서 받아와 부분적으로만 업데이트를 하는 방식, 하나의 어플리케이션을 사용하는 것 같이 사용자의 사용성을 증대하였다. + +computer의 성능향상과 js의 표준화가 되며 강력한 community(angular, react, vue)가 생성되어 csr 시대로 접어들게 된다. + +CSR(Client Side Rendering) - 클라이언트 측에서 다하는 것, 서버에서 index.html 파일을 보내주는데, 이 index.html 파일에는 빈 html 파일과 어플리케이션에서 필요한 js파일 링크만 있다. 이 js 파일에는 어플리케이션에서 필요한 로직들 뿐 아니라, 어플리케이션을 구동하는 라이브러리/프레임워크에 해당하는 소스코드들도 포함되어 있다. 따라서 굉장히 사이즈가 커 다운받는데 시간이 오래 걸린다. 이로 인한 문제점은 아래와 같다. +문제점 1: 사용자가 첫화면을 보기까지 시간이 오래 걸릴 수 있다는 것 +문제점 2: 좋지 않은 SEO(Search Engine Optimization) + +SSR(Server side Rendering) - 클라이언트에서 모든 것을 처리하는 것과는 다르게 웹 사이트에 접속했을 때, server에서 html파일을 만들고 이 파일에 조금 동적으로 제어할 수 있는 js파일을 넣어 client에 보내준다. +장점1: 초기 페이지 로딩이 빠르다. +장점2: 모든 컨텐츠가 html에 담겨져 있어 좋은 SEO, + +문제점 1: Blinking Issue(깜빡 거리는 현상) // 페이지 전체를 서버에서 다시 받아와 교체하는 방식. 이로 인해 페이지간 교체될 때 깜빡거리는 현상이 발생되고 이는 ux를 떨어뜨린다. +문제점 2: 서버 과부화(Server side overhead) +문제점 3: (가장 치명적) 빠르게 웹사이트를 확인할 수 있지만, 동적으로 데이터를 처리하는 js를 아직 다운로드 받지 못해 클릭해도 반응이 없을 수가 있다. +TTV(Time To View) +TTI(Time To Interact) + +CSR의 경우 - TTV,TTI 동일(사용자가 화면을 볼 수 있는 동시에, 클릭을 하는 인터랙션이 가능하다) +SSR의 경우 - TTV(서버에서 이미 만들어 놓은 html 파일로, 화면은 바로 볼 수 있다)와 TTI 간에 시간차가 존재 + +=> TTV, TTI는 웹사이트 성능을 분석할 때 사용되는 메트릭이다. + +CSR - 최종적으로 번들링해서 사용자에게 보내주는 js 파일을 어떻게 하면 효율적으로 분할해서 처음 사용자가 봐야하는 필수적인 요소만 담을 수 있도록 고민해야한다. +SSR - tti/ttv의 시간 단차를 줄이는 방법에 대해 고민 + +SSG (Static Site Generation) - React + Gatsby를 활용해 파일을 먼저 생성해서 서버에 배포해놓도록 하며 동적으로 필요한 부분도 이후 서버에서 가져올 수 있다. diff --git a/web/electron.md b/web/electron.md new file mode 100644 index 0000000..ae65af0 --- /dev/null +++ b/web/electron.md @@ -0,0 +1,39 @@ +## 일렉트론 +![Image](https://github.com/user-attachments/assets/4efa56bc-d624-4b87-954f-fe5f1eac8074) + +### 작동 방식 + - 일렉트론에는 두가지 프로세스 존재: 메인(Main) 프로세스와 렌더러(Renderer) 프로세스. + - 일렉트론 앱은 단 하나의 메인 프로세스를 가지며, Node.js 기반으로 동작하고 여러 렌더러 프로세스들을 관리한다. + - 각각의 렌데러 프로세스는 서로 독립적으로 작동한다. + - 메인 프로세스는 ipcMain 이라는 IPC 모듈을 통해, 렌더러 프로세스는 ipcRenderer 라는 IPC 모듈을 통해 메인 프로세스와 렌더러 프로세스가 통신이 이뤄지도록 한다. + ![Image](https://github.com/user-attachments/assets/d3fbd2b0-4e36-4b0e-94af-e9ebaba5bb3b) + + - IPC(Inter-Process Communication)란 프로세스간(Main <-> Renderer) 통신을 의미 + - IPC는 `on`을 통해 메시지 또는 이벤트를 수신하고, `send`를 통해 메시지 또는 이벤트를 전달한다. + - ipcMain에서는 `send`가 아닌 reply로 회신하거나, webContents의 send를 사용하여 회신한다. + +### 구성 요소 + - 화면을 그리기 위해선 '렌더러 프로세스'를 생성해야하는데, 이 렌더러 프로세스는 대표적으로 BrowserWindow 객체를 사용하여 생성한다. +``` + const { BrowserWindow } = require('electron'); + const win = new BrowserWindow({ width: 800, height: 600 }); +``` + + - BrowserWindow 객체는 여려 속성들을 제공하는데, 그중 webContents라는 것이 있다. + - 이 webContents는 EventEmitter를 상속받기 때문에 렌더러 프로세스에서 발생하는 여러 이벤트를 감지할 수 있다. + + - 화면을 그리는 또다른 방법으로 BrowserView 객체를 사용하는 것이다. + - 위에서 언급했던 BrowserWindow는 하나의 윈도우 창을 의미하며, 렌더러 프로세스에서의 가장 큰 단위이다. + - 경우에 따라 BrowserView를 사용하지 않고, BrowserWindow만으로도 프로그램을 충분히 구성 가능하다. + - 그런데..!! 하나의 윈도우 안에서 여러 영역을 나눠 표현해야하는 경우, 'BrowserView'를 사용할 수 있다. + - BrowserWindow를 통해 렌더러 프로세스를 생성하는 경우에는 높이, 넓이를 설정해야하지만 BrowserView는 높이, 넓이, BrowserView를 그릴 BrowserWindow의 특정 위치 또한 지정해줘야한다. + +### 프로세스 간 상태 공유 + - 하나의 윈도우(BrowserWindow) 안에 여러 개의 뷰(BrowserView)를 구성한다는 것은 하나의 화면에 여러 개의 브라우저를 띄우는 것과 동일하다. + - 하지만 각각의 뷰는 독립적으로 존재하기에 A뷰의 상태 값은 B뷰에서는 알 수 없다. + - 특정 뷰의 상태 값 혹은 상태 값의 변화는 자신을 제외한 다른 뷰에 전달하는 동작을 통해 공유한다. + - 각각의 렌더러 프로세스는 독립적으로 동작하기 때문에, BrowserWindow와 BrowserView 같은 렌더러 프로세스 간의 직접적인 통신이 불가능하다. + ![Image](https://github.com/user-attachments/assets/f461be3e-27c8-4eb3-9713-30e24ab47274) + + - 이러한 상황으로 인해 뷰 간의 상태 값을 공유하기 위해선 메인 프로세스를 사용해야 한다. + ![Image](https://github.com/user-attachments/assets/5d00a417-3543-4bb3-9f4b-0a46865c06a0) diff --git a/web/readme.md b/web/readme.md new file mode 100644 index 0000000..b698b61 --- /dev/null +++ b/web/readme.md @@ -0,0 +1,213 @@ +* Crontab이란? + + ``` + 시스템 관리자는 보안이나 시스템의 관리 등을 위해 주기적으로 동일한 작업을 반복 수행해야함. + +cron이란 리눅스에서 특정 시각에 명령이나 프로그램이 수행되도록 하는 리눅스용 작업 스케줄러이다. +미리 구성된 시간에 실행되도록 작업을 할당하는 스케줄링 도구가 크론이다. +이것으로 일정한 간격으로 시스템에서 수행될 일들을 자동화 할 수 있다. + ``` + + +* 지디웹 + + - 참가방법: https://www.gdweb.co.kr/sub/process.asp + + - 위 사이트에서 소개하는 내용을 중점적으로 사이트를 만들어야 할 것 같다. + + +* encodeURI, encodeURIComponent 차이 + + - encodeURI는 알파벳, 0~9의 숫자, ; , / ? : @ & = + $ # - _ . ! ~ * ' ( )를 제외한 문자를 인코딩(이스케이프 처리) + + - encodeURIComponent는 알파벳,0~9의 숫자 - _ . ! ~ * ' ( ) 를 제외한 문자를 이스케이프 처리 + + -> 두 함수의 차이는 / ? : @ & = + $ # 도 이스케이프 처리를 해버리는 지 여부에 있다. + + - & ? 와 같이 uri에서 특수한 기능을 하는 문자는(eg, ?는 uri에서 query string을 의미함) 인코딩하면 안되므로 path 전체를 인코딩할 때는 encodeURI를 사용. + + 파라미터 값에 & 등의 특수문자가 값으로 들어갈 때는 인코딩해줘야 하기에, 파라미터 값에는 encodeURIComponent 사용 + + ``` + const name = "co&ding"; // uri 파라미터 name으로 들어갈 값 + const uri = "http://javascript.com?name=" + encodeURIComponent(name) // 파라미터 값만 인코딩 + ``` + + cf) + + - 인코딩: 어떤 네트워크에서도 사용할 수 있게 문자를 코드(ASCII, 유니코드 등)로 변환하는 것 + + - 이스케이프: 문자열을 인코딩하는 것 + +* 애드온(add-on) + + cf) https://documenies.com/10 + +* 도메인 샤딩(domain sharding) + + - sharding: 조각, 파편을 뜻한다. + + - resource를 여러 개의 domain으로 나누어 저장하여, page load time을 향상시키는 일종의 트릭 혹은 방법이다. + + - 여러 개의 domain으로 나누어진 리소스를 다운받기 때문에 browser는 더 많은 리소스를 한번에 더 많이 받을 수 있다. + + - Domain sharding을 적용하는 이유는 대부분의 web browser가 한 개의 domain에 대해 active connection을 제한하기 때문이다. + + - 정적 파일(이미지, css, js 등)의 로딩 속도를 개선하는 방법으로 여러 개의 서브 도메인을 생성해 정적파일을 병렬로 가져온다고 한다. + + - 이러한 도메인 샤딩의 등장 배경은 HTTP/1.x 버젼에서 도메인 하나 당 동시에 요청할 수 있는 개수 제한이 있었기 때문이라고 한다. + + - 최신 브라우저들은 보통 한 도메인에 약 6개의 동시 다운로드를 제공한다. 이 갯수를 초과하는 페이지의 경우, 갯수를 6으로 나눈 도메인에 리소스를 뿌려두면, parallel하게 리소스들을 다운받을 수 있다. + + - Domain sharding이 항상 좋은 것은 아니다. performance loss를 유발하기도 한다. + + - web browser는 DNS loopup을 추가 domain에 대해서 수행해야하고, 각 domain에 대해서 connection을 유지해야 한다. 그래서 최초 initial load time은 기렁질 수 있다. + + - 2~4 개의 domain이 최적의 비율이라고 한다. 따라서 무조건 많은 domain이 좋은 것은 아니다. + + - SPDY는 제한없는 동시 요청이 가능하기 때문에, domain sharding을 해결할 수 있다. SPDY를 정식 지원하기 전까지는 domain sharding이 효율적일 수 있으나, SPDY를 도입하면서부터는 overhead 문제로 오히려 domain sharding을 제거하는 것이 추천된다. + + cf) + + https://wonism.github.io/domain-sharding/ + + https://aroundck.tistory.com/5153 + + +
+ +* GNB, LNB란? + + - GNB, LNB, FNB 는 매장에서 고객들이 자주 찾는 물건을 눈에 잘 띄는 위치에 배치해 빠른 구매를 이끌어내듯이, 웹 사이트에서 고객이 찾는 카테고리를 빠르게, 어디서나 확인할 수 있도록 하는 구성을 뜻한다. + + - GNB(Global Navigation Bar) + + - 웹 사이트 전체에 동일하게 적용되는 네비게이션 바 + + - 보통 웹사이트 최상단에 위치하며 어떤 페이지를 클릭해도 동일하게 보여진다. + + - 웹사이트가 제공하는 모든 서비스를 표현하며, 직관적으로 구성하는 것이 좋다. + + - LNB(Local Navigation Bar) + + - GNB를 클릭하거나 호버 했을 때 나오는 하위 카테고리 리스트 + + - FNB(Foot Navigation Bar) + + - GNB와 동일하게 모든 웹페이지 가장 하단에 위치한 내비게이션 바 + +
+ + cf) SNB(Side Navigation Bar): 왼쪽 혹은 오른쪽에 위치하며, 메인 메뉴, 서브메뉴를 제외한 기타 메뉴로 구성하여 사이드 메뉴라고 할 수 있다. + +
+ +* webpack5 module federation + + - module federation은 여러 분리된 빌드들이 하나의 앱을 구성할 수 있는 Webpack5의 새로운 기능이다. + + - 하나의 앱이 다른 빌드에 있는 코드를 동적으로 실행시킬 수 있는 기술이다. + + - micro-frontends의 근간이 되는 기술이기도 하다. + + - 특정 빌드가 remote 앱이 되고 그 앱에서 다른 빌드들을 동적으로 불러와 사용할 수 있다. remote는 꼭 특정한 하나의 빌드만 될 수 있는 것이 나이고, federated된 모든 빌드들이 remote가 될 수 있다. 즉 양방향(bidirectional)으로 module federation이 가능하다. 가령 a 빌드에서 b 빌드에 있는 코드를 실행시킬 수 있고, b빌드에서도 a빌드에 있는 코드를 실행시킬 수 있다. + + cf) federated 란? + + - https://medium.com/curg/%EC%97%B0%ED%95%A9-%ED%95%99%EC%8A%B5-federated-learning-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%B1%8C%EB%A6%B0%EC%A7%80-b5c481bd94b7 + + - https://module-federation.github.io/blog/get-started + +
+ +* CLS(Cumulative Layout Shift)란? + + - CLS(누적 레이아웃 이동)는 페이지의 전체 수명 동안 발생하는 모든 예기치 않은 레이아웃 이동에 대해 가장 큰 레이아웃 이동 점수 버스트를 뜻한다. // 사용자에게 발생하는 레이아웃 이동(layout shift) 빈도를 측정 + + - 방문자에게 콘텐츠가 얼마나 불안정한 지 측정하는 사용자 경험 측정 항목 및 웹 페이지의 성능 측정 지표이다. + + - 레이아웃 이동은 시각적 요소가 렌더링된 프레임에서 다음 프레임으로 위치를 변경할 때마다 발생한다. + + - 뷰포트에서 이동한 콘텐츠의 양과 영향을 받은 요소가 이동한 거리를 확인하여 점수로 표시한다.(CLS 점수, 좋은 사용자 환경을 제공하려면 사이트의 CLS 점수가 0.1 미만이여야 한다.) + + - 레이아웃 이동이 발생하는 원인 + + * 치수가 없는 이미지 + + * 크기가 없는 광고, 삽입 및 iframe + + * 동적으로 삽입된 컨텐츠 + + * FOIT / FOUT을 유발하는 웹 글꼴 + + * DOM을 업데이트하기 전에 네트워크 응답을 기다리는 작업 + + cf) + + * https://wit.nts-corp.com/2020/12/28/6240 + + * https://web.dev/i18n/ko/cls/ + +
+* 메시지 브로커, 이벤트 브로커의 차이 + + [ 메세지 브로커 ] + + - 이벤트 브로커로 역할을 할 수 없다. + + - 미들웨어 아키텍처에서 사용된다. (미들웨어는 서비스하는 애플리케이션들을 효율적으로 연결한다. ex, 메시징 플랫폼, 인증 플랫폼, 데이터베이스 등) + + - 메세지 브로커에 있는 큐에 데이터를 보내고 받는 프로듀서와 컨슈머를 통해 메세지를 통신하고 네트워크를 맺는 용도로 사용 + + - 메세지를 받아서 처리하고 나면 즉시 또는 짧은 시간 내에 삭제되는 구조이다. + + - 레빗엠큐, 레디스 큐 + + [ 이벤트 브로커 ] + + - 메시지 브로커로 역할을 할 수 있다. + + - 이벤트 또는 메시지라고 불리는 이 레코드(장부)를 딱 하나만 보관 + + - 인덱스를 통해 개별 액세스를 관리한다. + + - 업무상 필요한 시간동안 이벤트를 보존할 수 있다. + + - 카프카, aws의 키네시스 + + +이벤트 브로커는 서비스에 나오는 이벤트를 마치 DB에 데이터를 저장하듯 이벤트 브로커의 큐에 저장한다. + +이렇게 데이터를 저장함으로써 얻는 장점이 있다. + +1. 단일 진실 공급원으로 사용할 수 있다. +2. 장애가 발생했을 때, 장애가 일어난 지점부터 재처리할 수 있다. +3. 많은 양의 실시간 스트림 데이터를 효과적으로 처리할 수 있다는 특징이 있다. + +이벤트 브로커로 클러스터를 구축하면 이벤트 기반 마이크로 서비스 아키텍쳐로 발전하는데 아주 중요한 역할을 할 뿐만 아니라 메세지 브로커로서도 사용할 수 있다. + +
+ +* stateless VS statefull + + - stateless + + - stateless 프로세스, 어플리케이션은 과거 트랜잭션에 대한 정보 또는 참조가 저장되지 않는다. + + - 스테이트리스 애플리케이션은 하나의 서비스 또는 기능을 제공하며, 콘텐츠 전달 네트워크(CDN), 웹, 프린트 서버를 사용해 단기 요청을 처리한다. + + - 가령 검색창에 질문을 입력하고 엔터키를 누르는 형식으로 진행되는 온라인 검색이 대표적이다. + + - 트랜잭션이 우발적으로 중단되거나 종료되면 새롭게 시작하면 된다. + + - 스테이트리스 트랜잭션은 단일 요청에 대해 하나의 응답이 나온다. + +
+ + - statefull + + - 스테이트풀 프로세스, 어플리케이션은 온라인 뱅킹이나 이메일처럼 여러번 반환될 수 있다. + + - 스테이트풀은 이전 트랜잭션의 컨텍스트에 따라 수행되며, 현재 트랜잭션이 이전 트랜잭션에서 발생한 상황에 영향을 받는다. 이러한 이유로 스테이트풀 어플리케이션은 사용자에게 받은 요청을 처리할 때마다 같은 서버를 사용한다. + + - 스테이트풀 트랜잭션은 컨텍스트와 내역이 저장되기에 중단되어도 중단된 곳부터 다시 시작할 수 있다.