방법이 두가지가 있었다.

1. 다음 우편번호 서비스 API 사용하기(react-daum-postcode)

https://www.npmjs.com/package/react-daum-postcode

 

react-daum-postcode

Daum Postcode service for React. Latest version: 3.1.3, last published: a year ago. Start using react-daum-postcode in your project by running `npm i react-daum-postcode`. There are 24 other projects in the npm registry using react-daum-postcode.

www.npmjs.com

 

2. 카카오 우편번호 서비스에서 제공해주는 가이드보고 활용하기

https://postcode.map.daum.net/guide

 

Daum 우편번호 서비스

우편번호 검색과 도로명 주소 입력 기능을 너무 간단하게 적용할 수 있는 방법. Daum 우편번호 서비스를 이용해보세요. 어느 사이트에서나 무료로 제약없이 사용 가능하답니다.

postcode.map.daum.net

 

나는 1번 방식을 활용하다가 사용해야하는 속성이 있어서 2번 방식으로 바꾸었다.

간편한 건 1번이 더 간편한데 다양하게 활용하려면 2번 방식이 더 좋은 듯


1번 방식 : 다음 우편번호 서비스 API (react-daum-postcode) 사용하기

- 설치

yarn add react-daum-postcode

or

npm install react-daum-postcode

 

- 리액트 컴포넌트 처럼 <DaumPostcode /> 컴포넌트를 import해서 사용할 수 있다.

import DaumPostcode from 'react-daum-postcode';

const Postcode = () => {
  return (
    <div>
      <DaumPostcode />
    </div>
  );
}

 

모달창이 열리면 DaumPostcode 컴포넌트가 보이도록 하고, 주소 입력이 완료되면 completeHandler 함수 실행

completeHandler 함수

도로명주소랑 상세주소만 받으면 됐어서 주소 입력 완료시에 도로명 주소 상태만 업데이트하고

이후 상세주소도 입력 받으면 업데이트 되도록 구현했었다.


전체코드

 

이후 data는 아래와같이 돌아오는데 여기서 address랑 sido, sigungu도 백엔드에 넘겨야 했음

그런데 지금 sido는 "경기"로 되어있는데 이걸 백엔드는 "경기도" 형태로 받고 싶어했고

알아보니 아래 shorthand라는 속성으로 기본 축약 표시되어있는 것을 false 처리하면 된다고 했다.

기본적으로 shorthand는 true 처리 되어있어서 경기, 서울 이런식으로 표시됨

 

그래서 해당 속성으로 사용하려고 하니 .. 이 방법으로는 안되는 것같고 2번으로 사용해야해서 급하게 구현을 변경했다.

 

2번 방식 : 가이드보고 활용하기

먼저 아래 스크립트를 index.html 에 추가한다.

<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>

index.html

나는 위 방식을 사용했는데 코드를 리액트 형태로 바꾸고 나한테 필요한 값만 가져와서 사용했다.

버튼 클릭하면 handleAddressSearch 함수가 실행되는데

여기서 new window.daum.Postcode(~~~~) 이 안에서 내가 원하는 것을 할 수 있었던 것

onComplete는 주소 다 입력받고나서 실행되고

나에게 필요한 건 shorthand:false 였다.. 저거 쓰려고 코드를 다 바꿈 ㅡㅡ 

그래도 하니까 sido가 원하는 "경기도" 형태로 돌아온다 !

해당 값을 백엔드에 넘기기만 하면 끝 ~

전체코드

해당 속성말고도 여기서는 사용할 수 있는 속성이 많은 것 같다.

다양하게 활용하고 싶으면 가이드보고 따라하는 것을 추천한다. 근데 1번 방식이 엄청 간편하긴 함.

 

TypeScript is JavaScript with syntax for types
자바스크립트 문법에 타입을 가미한것이 타입스크립트이다.

 

타입스크립트는 자바스크립트의 한계를 벗어나 타입 체크를 정적으로 런타임이 아닌 빌드 타임에 수행할 수 있게 해준다.

런타임까지 가지 않더라도 코드를 빌드하는 시점에서 이미 에러가 발생할 가능성이 있는 코드를 확인할 수 있다.


타입스크립트 활용법

any 대신 unknown을 사용하자

  • any
    • 모든 타입을 허용하므로 타입 안전성이 낮다.
    • 타입 추론이 어렵다.
  • unknown
    • 모든 타입을 허용하지만, 실제 사용 타입 검사가 필요하므로 타입 안전성이 높다.
    • 다른 타입으로 좁혀질  있어, 타입 추론이 용이하다. 

타입 가드를 적극 활용하자

조건문 + 타입가드를 사용하면 타입을 효과적으로 좁힐 수 있어 조금 더 명확하게 사용할 수 있다.

instanceof : 지정한 인스턴스가 특정 클래스의 인스턴스인지 확인할 수 있는 연산자
typeof : 특정 요소에 대해 자료형을 확인하는데 사용
in : property in object로 사용되며, 주로 어떤 객체에 키가 존재하는지 확인하는 용도

 

제네릭(generic)

단일 타입이 아닌 다양한 타입에 대응할 수 있도록 도와주는 도구, 타입을 변수화 한 것

function getFirstAndLast<T>(list: T[]) : [T, T] {
  return [list[0], list[list.length - 1]]
}

const [first, last] = getFirstAndLast([1,2,3,4,5])

first // number
last // number

const [first, last] = getFirstAndLast(['a', 'b', 'c', 'd', 'e'])

first // string
last // string
  • 타입스크립트 컴파일러가 입력 배열의 타입을 자동으로 추론하여 T에 대입한다. 
  • 따라서 함수 반환값의 타입도 자동으로 추론되는 것이다.

타입스크립트 전환 가이드

tsconfig.json 먼저 작성하기

{
    // TypeScript 컴파일러의 옵션들을 지정하는 속성
    "compilerOptions": { 
        "outDir": "./dist", 
        "allowJs": true,
        "target": "es5", 
    },
    "include": ["./src/**/*"]
}
  • compilerOptions:
    • outDir: 컴파일된 JavaScript 파일이 ./dist 디렉토리에 출력, .ts나 .js가 만들어진 결과를 넣어두는 폴더
    • allowJs: .js 파일을 허용할 것인지 여부
    • target: 결과물이 될 js 버전을 지정
  • include: 트랜스파일할 js와 ts 파일을 지정한다.

JSDoc과 @ts-check를 활용해 점진적으로 전환하기

js 파일을 ts 로 전환하지 않더라도 타입을 체크할 수 있는 방법

하지만 JSDoc을 추가하는 것도 손이 가는 작업이기에 추천하지 않는다.

 

타입 기반 라이브러리 사용을 위해 @types 모듈 설치하기

타입스크립트로 작성되지 않은 코드에 대한 타입을 제공하는 라이브러리 @types 설치하기

.ts로 전환시 import에 "Cannot find modul 'lodash' or its corresponding type declarations" 에러가 출력된다면 반드시 설치

 

파일 단위로 조금씩 전환하기

상수와 유틸과 같이 별도의 의존성을 가지고 있지 않은 파일을 먼저 전환해보기

상수의 경우 string, number와 같이 원시값 대신 가능한 한 타입을 좁혀보는 것을 추천

구조 분해 할당

배열 또는 객체의 값을 말 그대로 분해해 개별 변수에 즉시 할당하는 것.

배열 구조 분해 할당  : 배열의 요소를 개별 변수에 할당하는 방법

기본 사용법 ▼

const array = [1, 2, 3, 4, 5]

let [first, second, third, fourth ,fifth] = array;
console.log(first); // 1
console.log(second); // 2
console.log(third); // 3
console.log(fourth); // 4
console.log(fifth); // 5

 

일부 요소 건너뛰기 ▼

쉼표를 사용하여 배열의 일부 요소 건너뛰기

const array = [1, 2, 3, 4, 5]

let [first, , , ,fifth] = array;
console.log(first); // 1
console.log(fifth); // 5

 

기본값 설정 ▼

배열의 요소가 undefined인 경우 기본값을 설정할 수 있다.

- 기본값을 사용하는 것은 a, e

a : 명시적으로 undefined 지정

e : 배열의 길이를 넘어서서 구조 분해 할당됐으므로 undefined 평가됨.

const [a=1, b=1, c=1, d=1, e=1] = [undefined, null, 0, '']
a // 1
b //null 
c // 0
d // ''
e // 1

 

Rest 패턴 ▼

나머지 요소를 하나의 배열로 모아서 할당

const array = [1, 2, 3, 4, 5]

let [first, second, ...arrayRest] = array;
console.log(first); // 1
console.log(second); // 2
console.log(arrayRest); // [3,4,5]

 

객체 구조 분해 할당 : 객체에서 값을 꺼내온 뒤 할당하는 것

배열 구조 분해 할당과 달리, 객체는 객체 내부 이름으로 꺼내온다는 것

const obj = {a:1, b:1, c:1, d:1, e:1}

const { a, b, c, ...objRest} = obj
// a 1
// b 1
// c 1
// objRest = {d:1, e:1}

 

새로운 이름으로 재할당, 배열과 마찬가지로 기본값을 주는 것도 가능하다.


전개 구문

배열이나 객체, 문자열과 같이 순회할 수 있는 값에 대해 말 그대로 전개해 간결하게 사용할 수 있는 구문

 

배열의 전개 구문

const arr1 = ['a', 'b']
const arr2 = [...arr1, 'c', 'd', 'e'] // ['a', 'b', 'c', 'd', 'e']

배열 내부에서 ...배열을 사용하면 해당 배열을 마치 전개하는 것처럼 선언하고 활용 가능

기존 배열에 영향을 미치지 않고 배열을 복사하는 것도 가능하다.

 

객체의 전개 구문

const obj1 = { a:1, b:2 }
const obj2 = { c:3, d:4 }

const newObj = { ...obj1, ...obj2 }
// { a:1, b:2, c:3, d:4 }

 

객체 전개 구문에 있어서 순서가 중요하다. 순서의 차이로 인해 값이 덮여쓰여질 수 있기 때문이다.

const obj = { a:1, b:2, c:3, d:4 }

const newObj = { ...obj, c:10 }
// { a:1, b:2, c:10, d:4 }

객체 전개 구문 이후에 c:10으로 값을 덮어씀.

const obj = { a:1, b:2, c:3, d:4 }

const newObj = { c:10, ...obj}
// { a:1, b:2, c:3, d:4 }

객체 전개 구문이 c:10의 값을 3으로 덮어씀.


객체 초기자

객체에 넣고자 하는 키와 값을 가지고 있는 변수가 존재한다면 해당 값을 간결하게 넣어줄 수 있는 방식이다.

const a = 1
const b = 2

const obj = {
	a, b
}
// { a:1, b:2 }

Array 프로토타입의 메서드 : map, filter, reduce, forEach

Array.prototype.map

인수로 전달받은 배열과 똑같은 길이의 새로운 배열을 반환하는 메서드

배열의 각 아이템을 순회하면서 각 아이템을 콜백으로 연산한 결과로 구성된 새로운 배열을 만들 수 있다.

const arr = [1, 2, 3, 4, 5]
const dbArr = arr.map((item) => item * 2)
// [2, 4, 6, 8, 10]

 

Array.prototype.filter

말 그대로 필터링 역할을 하는 메서드, 어떠한 조건을 만족하는 새로운 배열을 반환할 때 주로 사용

인수로 받는 콜백함수에서 truthy 조건을 만족하는 경우에만 해당 원소를 반환한다.

const arr = [1, 2, 3, 4, 5]
const evenArr = arr.filter((item) => item % 2 === 0)
// [2, 4]

 

Array.prototype.reduce

콜백 함수와 함께 초깃값을 추가로 인수를 받는데, 이 초깃값에 따라 배열이나 객체, 또는 그 외의 다른 무언가를 반환할 수 있는 메서드

콜백 함수를 실행하고, 이를 초깃값에 누적해 결과를 반환

const arr = [1, 2, 3, 4, 5]
const sum = arr.reduce((result, item) => {
	return result + item
}, 0)
// 15

0 > 결과를 누적할 초깃값

콜백 함수의

첫 번째 인수 : 앞서 선언한 초깃값의 현재

두 번째 인수 : 현재 배열의 아이템

>> 콜백의 반환값을 계속 초깃값에 누적하면서 새로운 값을 만드는 것.

 

Array.prototype.forEach

콜백 함수를 받아 배열을 순회하면서 단순히 그 콜백 함수를 실행하는 메서드

const arr = [1, 2, 3]

arr.forEach((item) => console.log(item))
// 1, 2, 3

 

※ 주의할 점

1. 반환 값이 없다. 단순히  그 콜백 함수를 실행할 뿐이다. 반환 값은 undefined로 의미가 없다.

2. 메서드가 실행되고 에러를 던지거나, 프로세스를 종료하지 않는 이상 이를 멈출 수 없다.


삼항 조건 연산자

3개의 피연산자를 취할 수 있는 문법

조건문 ? 참일 때 값 : 거짓일 때 값

조건부 렌더링 : if 조건문을 간단하게 쓸 수 있다는 점에서 리액트에서 자주 쓰인다.

※ 간단하지만 중첩해서 사용하면 가독성이 떨어지기 때문에 가급적이면 중첩해서 쓰지는 말자

싱글 스레드 자바스크립트

싱글 스레드는 자바스크립트의 코드의 실행이 하나의 스레드에서 순차적으로 이루어지는 것을 의미한다.

이는 코드를 한 줄 한 줄 실행하는 것을 의미하며, 궁극적으로 하나의 작업이 끝나기 전까지 뒤이은 작업이 실행되지 않는다는 것을 의미한다. 이러한 특징은 'Run-to-completion'이라고 하며, 동시성을 고민할 필요가 없다는 점에서는 아주 큰 장점이 된다.

 

자바스크립트는 싱글 스레드에서 동기방식으로 작동한다. 일반적으로 한 번에 하나의 작업을 처리할 수 있는 것이다.

동기 방식은 직렬 방식으로, 하나의 작업을 처리할 동안 다른 모든 작업은 대기한다.

 

과거에는 자바스크립트가 기초적인 수준에서만 제한적으로 사용되었기 때문에 싱글 스레드가 더 합리적인 방식이었다.

오히려 멀티 스레딩을 지원했다면 메모리 공유로 인해 동시에 같은 자원에 접근하는 타이밍 이슈 등의 문제가 발생했을 것이다.

 

하지만 현재 자바스크립트는 과거와 다르게 다양한 영역에서 사용되고 있기 때문에 설계가 바뀔 때가 됐다고 보기도 한다. 

그래서 나오게 된것이 비동기 방식이다.

비동기(asynchronous) 방식

비동기 통신은 병렬 방식으로 작업을 처리하는 것이며, 이는 한 번에 여러 작업이 실행될 수 있다는 것을 의미한다.

asynchronous, 동기식과 다르게 요청 즉시 결과가 주어지지 않을 수 있고 따라서 응답이 언제 올지도 알 수 없다.

 

이러한 비동기 처리를 가능하게 하는 것이 이벤트 루프이다.

이벤트 루프란?

  • 이벤트 루프는 JavaScript 런타임 외부에서 자바스크립트의 비동기 실행을 돕기 위해 만들어진 장치이다.
  • 이벤트 루프는 호출스택(call stack), 태스크 큐, 마이크로태스크 큐 등을 관리한다.
  • 비동기 코드(setTimeout, AJAX 요청 등)는 콜스택에서 실행되지 않고 Web API에서 처리된다.
  • 비동기 작업이 완료되면 콜백 함수가 태스크 큐에 추가되고, 이벤트 루프가 콜스택이 비어있을 태스크 큐의 함수를 실행한다.

비동기 이벤트 루프의 동작 과정

  1. 호출스택(Call Stack): 현재 실행 중인 함수를 관리하는 스택 자료구조. 함수가 호출되면 콜스택에 추가되고, 함수가 종료되면 콜스택에서 제거된다.
  2. Web API: 브라우저에서 제공하는 API, 비동기 작업(setTimeout, AJAX 요청 등)을 처리한다.
  3. 태스크 (Task Queue): 비동기 작업이 완료되면 콜백 함수가 태스크 큐에 추가된다.
  4. 마이크로태스크 (Microtask Queue): Promise then/catch/finally 콜백 함수가 마이크로태스크 큐에 추가된다.
  5. 이벤트 루프(Event Loop): 콜스택이 비어있을 때 이벤트 루프가 태스크 큐와 마이크로태스크 큐를 확인하고, 대기 중인 함수를 콜스택에 추가하여 실행한다.

태스크 큐 vs 마이크로태스크 큐

대기하는 작업의 종류

  • 태스크 큐: 일반적인 비동기 작업(setTimeout, AJAX, 이벤트 핸들러 등)의 콜백 함수
  • 마이크로태스크 : Promise 관련 작업(then, catch, finally)콜백 함수

우선순위

  • 마이크로태스크 큐의 작업 > 태스크 큐의 작업
  • 이벤트 루프가 호출스택이 비어있을 마이크로태스크 큐를 먼저 확인하고, 대기 중인 콜백 함수를 실행

클로저란? : 함수와 함수가 선언된 어휘적 환경(Lexical Scope)의 조합

function add() {
    const a = 10
    function innerAdd() {
        // innerAdd() 은 내부 함수이며, 클로저다.
        const b = 20
        console.log(a + b);
    }
    innerAdd();
    }
add();

함수가 중첩된 상황에서 a 변수의 유효범위는 add 전체이고, b 변수의 유효범위는 innerAdd 전체이다.

선언적 어휘적 환경이란, 변수가 코드 내부에서 어디서 선언됐는지를 말하는 것이다.


변수의 유효범위, 스코프(Scope)

변수의 유효범위에 따라서 어휘적 환경이 결정된다. 이러한 변수의 유효 범위를 스코프(scope)라고 한다.

 

1. 전역 스코프(global)

이름에서 알 수 있듯, 이 스코프에서 변수를 선언하면 어디서든 호출 가능하다.

 

2. 함수 스코프(Function-level scope)

함수 스코프는 함수 내부에서 선언된 변수가 해당 함수 내부에서만 접근 가능한 의미한다.

, 함수 내부에서 선언된 변수는 함수 외부에서 접근할 없다.

function hello() {
  var local = 'local variable'
  console.log(local) // local variable
}

hello()
console.log(local) // ReferenceError

함수 내부에서 선언된 local 변수는 함수 내부에서 접근 가능하지만 함수 외부에서는 접근할 수 없다.

var x = 10

function foo() {
  var x = 100
  console.log(x) // 100

  function bar() {
    var x = 1000
    console.log(x) // 1000
  }
  bar()
}

console.log(x) // 10
foo()

중첩 되어있을 경우 가장 가까운 변수를 참조한다. 전역 스코프의 x는 전역 변수인 x를 참조하게 된다.


 

리액트에서의 클로저

클로저의 원리를 사용하고 있는 대표적인 것 중 하나는 useState이다.

function Component() {
  const [state, setState] = useState()
  function handleClick() {
    setState((prev) => prev +1)
  }
}

useState 함수의 호출은 첫 줄에서 종료되었지만,

useState 내부에서 클로저가 활용되었기 때문에 setState는 계속해서 최신 값을 확인할 수 있는 것이다.

 

handleClick 함수는 클로저를 사용하여 이전 상태를 참조하고, 상태를 업데이트 할 수 있다.

클로저를 통해 컴포넌트의 렉시컬 스코프에 접근할 있어, 상태 관리와 업데이트가 효과적으로 이루어질 있는 것이다.

클로저를 활용하면 전역 스코프의 사용을 막고, 개발자가 원하는 방향으로 정보를 노출시킬 수 있다는 장점이 있다.

 

클래스란 무엇인가?

특정한 객체를 만들기 위한 일종의 템플릿과 같은 개념

즉, 특정한 형태의 객체를 반복적으로 만들기 위해 사용되는 것이 바로 클래스이다.

 

constructor : 객체를 생성하는 데 사용하는 특수한 메서드, 생성자 메서드

  • 하나만 존재
  • 생략 가능
  • 여러 개 사용시 에러
class Car {
	constrctor (name) {
    	this.name = name
    }
}

 

프로퍼티 : 클래스로 인스턴스를 생성할 때 내부에 정의할 수 있는 속성값

const myCar = new Car('자동차') // 프로퍼티 값 : 자동차

 

getter와 setter

  • getter : 클래스에서 무언가 값을 가져올 때 생성
  • setter : 클래스 필드에 값을 할당할 때 사용

인스턴스 메서드 : 클래스 내부에 선언한 메서드

  • 자바스크립트의 프로토타입에 선언되어 프로토타입 메서드라고도 함.

새롭게 생성한 객체에서 클래스에서 선언한 인스턴스 메서드에 접근할 수 있는 이유는, 메서드가 prototype에 선언되었기 때문이다.

class Car {
	constrctor(name) {
    	this.name = name
    }
    
    hello() {
    	console.log(`안녕하세요, ${this.name}입니다.`)
    }
}

클래스에서 인스턴스 메서드인 hello() 선언

const myCar = new Car('자동차')
myCar.hello() // 안녕하세요. 자동차입니다.

새롭게 생성한 객체 myCar에서 hello()에 접근할 수 있다. > 메서드가 prototype에 선언되었다.

 

정적 메서드 : 클래스의 인스턴스가 아닌 이름으로 호출

  • 객체를 생성하지 않더라도 여러 곳에서 재사용이 가능하다.
  • 인스턴스를 생성하지 않아도 사용할 수 있다.
  • 인스턴스에서 접근할 수 없다.
class Car {
	static hello() {
    	console.log(`안녕하세요.`)
    }
}

const myCar = new Car()

myCar.hello() // TypeError
Car.hello() // 안녕하세요.

 

상속 : 기존 클래스를 상속받아서 자식 클래스에서 상속 받은 클래스를 기반으로 확장하는 개념

  • 기존 클래스를 확장하여 새로운 클래스를 만드는 것
  • extends 키워드를 사용하여 상속 구현.

A클래스를 extends한 B클래스가 생성한 객체에서도, B클래스가 따로 정의하지 않은 A클래스의 메서드를 사용할 수 있고, A클래스를 기반으로 다양하게 파생된 클래스를 만들 수 있다.

 

직접 객체에 선언하지 않았음에도 프로토타입에 있는 메서드를 찾아 실행을 도와줄 수 있는 이유는 프로토타입 체이닝덕분이다.

객체가 특정 속성을 찾을 때 자기 자신부터 시작해서 프로토타입을 타고 최상위 객체인 Object까지 훑기 때문이다.

1.2.1 함수란 무엇인가?

하나의 블록으로 감싸서 실행 단위로 만들어 놓은 것

1.2.2 함수를 정의하는 4가지 방법

1. 함수 선언문

  • 일반적인 함수 선언과 비슷
  • 함수 이름을 명시하여 정의하는 방식
  • function myFunction()

2. 함수 표현식

  • 함수를 변수에 할당하는 방식
  • var myFunc = myFunction()

함수 선언문 vs 함수 표현식

    • 호이스팅(Hoisting)
      • 함수 선언문 : 호이스팅의 영향을 받아 함수 전체가 끌어올려짐. 선언 전에도 함수 호출 가능
      • 함수 표현식 : 변수 선언만 호이스팅되어 선언 전에 호출하면 undefined
  • 함수 이름 사용 여부
    • 함수 선언문 : 함수 이름을 사용
    • 함수 표현식 : 함수 이름 생략 가능 (오히려 함수에 이름을 주는 것은 방해 요소가 된다.)

3. Function 생성자

const add = new Function('a', 'b', 'return a+b')

add(10, 24)
  • Function 생성자를 활용하는 방식
  • 매개변수, 함수의 몸통을 모두 문자열로 작성해야하기 떄문에 권장하지 않는다.
  • 거의 사용되지 않는 방식

4. 화살표 함수

  • 화살표를 사용하여 만드는 함수. 간결하고, 가독성 좋음
  • 생성자 함수로 사용 불가능 (constructor 사용 불가능) 
 const Car = (name) => {
    this.name = name
  }
  const myCar = new Car('안녕') // TypeError
  • new 연산자로 호출 불가
  • 자신만의 this 값을 가지지 않기 때문
  • 화살표 함수의 this는 상위 스코프의 this를 가리키게 된다.
  • arguments 객체 사용 불가능 (arguments 객체 : 함수에 전달된 인수들을 배열과 유사한 형태로 저장하고 있는 객체)
const hi = () => {
    console.log(arguments)
  }
  hi(1,2,3) // ReferenceError : arguments is not defined
  • arguments 객체가 자동으로 생성되지 않기 때문에 인자를 정확하게 넘겨주지 않으면 Error
const hi = (...rest) => {
  console.log(rest) // [1,2,3]
}
hi(1,2,3)
  • arguments 대신에 Rest 매개변수를 사용할 수 있음. (전달된 모든 인수를 배열로 받음)

1.2.3 다양한 함수 살펴보기

1. 즉시 실행 함수

  • 말 그대로 함수를 정의하고 그 순간 즉시 실행되는 함수
  • 단 한 번만 호출되면 다시금 호출할 수 없다. (재사용 X)
  • 선언만으로 실행이 그 자리에서 끝난다는 것을 알 수 있기 때문에 리팩터링에도 도움.
(function (a,b) {
  return a + b
})(10, 24) // 34

((a, b) => {
  return a + b
})(10, 24) // 34

 

2. 고차 함수

  • 함수를 변수에 할당하거나, 함수의 인자로 전달하거나, 함수의 반환값으로 사용 가능

1.2.4 함수를 만들 때 주의해야 할 사항

1. 함수의 부수 효과를 최대한 억제하라

  • 부수 효과(side-effect) : 함수 외부에 영향을 끼치는 것
  • 순수 함수 : 부수 효과가 없는 함수
  • 순수 함수는 언제 실행되든 항상 결과가 동일하기 때문에 예측 가능하며 안정적임.
  • 예측 가능한 단위의 부수 효과가 작은 함수를 설계하면, 유지보수가 쉬워진다.

2. 가능한 한 함수를 작게 만들어라

  • 함수는 하나의 일을, 하나만 잘하면 된다.(Do One Thing and Do It Well)
  • 하나의 함수에서 너무 많은 일을 하게 하지 말 것
  • 코드의 길이가 길어질수록
    • 코드 냄새(문제를 일으킬 여지가 있는 코드)가 날 확률이 커지며,
    • 무슨 일이 일어나는지 예측할 수 없다.

3. 누구나 이해할 수 있는 이름을 붙여라

  • 가능한 한 함수 이름은 간결하고 이해하기 쉽게.

1.2.5 정리

함수 : 하나의 블록으로 감싸서 실행 단위로 만들어 놓은 것

 

함수를 정의하는 4가지 방법

  • 함수 선언문
  • 함수 표현식
  • Function 생성자
  • 화살표 함수

다양한 함수

  • 즉시 실행 함수
  • 고차 함수

함수를 만들 때 주의사항

  • 함수의 부수 효과를 최대한 억제하라
  • 가능한 한 함수를 작게 만들어라
  • 누구나 이해할 있는 이름을 붙여라

1.1.1 자바스크립트의 데이터 타입

원시 타입(primitive type) - 객체가 아닌 모든 타입

Undefined

  • 변수가 선언되었지만 값이 할당되지 않은 경우
  • 선언됐지만 할당되지 않은 값
  • 객체의 존재하지 않는 프로퍼티에 접근할 때
let foo // 선언되었지만 값이 할당되지 않음.
typeof foo === 'undefined'
function bar(hello) {
  return hello
}
typeof bar() === 'undefined' // hello 매개변수가 전달되지 않음

 

null

  • 아직 값이 없거나 비어있는 값
  • 명시적으로 비어있음을 나타내는 값
  • 존재하지 않음. 
let someVar = null; // 명시적으로 아무것도 없음을 나타냄.
typeof someVar === 'Object' // JS의 버그.
// 이전 코드에서 작동할 수 없는 호환성이 깨지는 변경사항이어서 받아들여지지 않음.

 

 

Boolean

  • True / False만을 가질 수 있는 데이터 타입
  • 주로 조건문에서 많이 사용
  • Truthy / Falsy (조건문 안에서 True / False로 취급되는 값)
    • Falsy : false, 0, -0, NaN, '', null, undefined
    • Truthy : true, 1, [], {} (객체와 배열은 내부에 값이 존재하는지 여부와 상관없이 truthy)

Number

  • 정수, 실수를 모두 포함
  • 안전 범위 : -(253 - 1) ~ 253 - 1

String

  • 텍스트 타입의 데이터를 저장
  • 표현방법 : 작은 따옴표('), 따옴표("), 백틱(`)
    • 백틱(`) : 템플릿 리터럴(template literal)
      • 문자열 가능
      • 문자열 내부에 표현식 가능
const longText = `
  안녕하세요!
  ` // 줄바꿈 가능. ', " 은 불가능

 

Symbol 

  • ES6에서 도입된 새로운 원시 타입
  • 중복되지 않는 어떤 고유한 값을 나타내기 위함
const key1 = Symbol('key')
const key2= Symbol('key')
key1 === key2 // False > 같은 인수를 넘겨주더라도 동일 값으로 인정 X 
// 동일 값을 사용하기 위해서는 Symbole.for 활용
Symbol.for('hello') === Symbole.for('hello') // true

 

Bigint

  • ES2020에서 도입된 새로운 원시 타입
  • Number 타입의 안전 범위를 벗어나는 정수를 표현할 사용

객체/참조 타입(object/reference type) - 원시타입 이외의 모든 . (배열, 함수, 정규식, 클래스)

object

const hello1 = () => {
}
const hello2 = () => {
}
hello1 === hello2 // False > 내용은 같아보여도 참조가 다르다.

1.1.2 값을 저장하는 방식의 차이

원시 타입

  • 불변 형태의 값으로 저장
  • 변수에 원시 타입의 값을 할당할 때, 해당 값은 메모리 영역에 직접 저장
  let hello = 'hello World'
  let hi = hello // hello World라는 '값'이 전달

  console.log(hello === hi) // true

 

객체

  • 변경 가능한 형태로 저장
  • 객체를 다른 변수에 할당할 때, 값이 아닌 참조가 전달
  • 즉, 객체의 실제 내용이 아닌 객체를 가리키는 참조가 전달
let hello = {
    greet: 'hello World!'
}  

let hi = {
    greet: 'hello World!'
}

console.log(hello === hi) // false > 서로 다른 참조를 바라보고 있음.
console.log(hello.greet === hi.greet) // true > 원시 값인 내부 속성값은 동일
let hello = {
    greet: 'hello World!'
}  

let hi = hello
console.log(hello === hi) // true > 동일한 객체를 바라보고 있음.
  • 변수에 저장된 것은 실제 객체가 아닌 객체의 메모리 주소이다.
  • 따라서 객체를 복사할 때 참조가 복사되어, 원본 객체와 복사본 객체가 동일한 객체를 가리키게 되는 것

1.1.3 자바스크립트의 또 다른 비교 공식, Object.is

ES6에 도입된 메서드로, 두 값의 동등성을 판단

  • == (느슨한 비교) : 자동 형 변환 수행
  • === (엄격한 비교) : 자동 형 변환 없이 비교
  • Object.is() : === 와 유사하지만, 몇가지 차이점 존재.
    • +0 === -0 > true이지만, Object.is(+0, -0) > false
    • NaN === NaN > false이지만, Object.is(NaN, NaN) > true
    • 부동 소수점, 특수 값 비교에 유용하지만, 객체 비교에는 적합하지 않다.
      • === 가지는 한계를 극복하기 위해 만들어 졌지만,
        여전히 객체 비교에 있어서는 JS 특징으로 인해 === 동일하게 동작하기 때문.

1.1.4 리액트에서의 동등 비교

얕은 비교 수행

  • 리액트는 props에서 꺼내온 값을 기준으로 렌더링을 수행하기 때문에 얕은 비교로 충분
  • 객체 간 얕은 비교 : 객체의 첫 번째 깊이에 존재하는 값만 비교하는 것
  • 1 depth 까지 비교 가능
import is from './objectIs';
import hasOwnProperty from './hasOwnProperty';

function shallowEqual(objA: mixed, objB: mixed): boolean {
    // is() 함수로 두 객체가 정확히 동일한지 확인.
    if (is(objA, objB)) {
        return true;	
    }



  // 두 인자가 모두 객체 타입인지 확인
  if (
    typeof objA !== 'object' ||
    objA === null ||
    typeof objB !== 'object' ||
    objB === null
  ) {
    return false;
  } 

  // 두 객체의 키 개수가 동일한지 확인
  // 각 키의 배열을 꺼냄
  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB); 

  // 배열의 길이가 다르다면 false
  if (keysA.length !== keysB.length) {
    return false;
  }

  //두 객체의 각 키에 대해 값 비교, 하나라도 다르면 false
  for (let i = 0; i < keysA.length; i++) {
    const currentKey = keysA[i];
    if (
      !hasOwnProperty.call(objB, currentKey) ||
      !is(objA[currentKey], objB[currentKey])
    ) {
      return false;
    }
  }
  return true;
}

export default shallowEqual;

 

  • hasOwnProperty() 메서드는 객체가 특정 프로퍼티를 가지고 있는지 확인하는 데 사용

1.1.5 정리

데이터 타입

원시 타입 (불변형태의 값 저장, 메모리영역 차지)

1. Undefined

2. null

3. Boolean

4. Number

5. String

6. Symbol

7. Bigint

 

객체(참조) 타입 (변경가능한 형태로 저장, 참조를 전달)

1. Object


Object.is() : ES6에서 새롭게 도입된 비교 문법 (객체 비교에는 적합하지 않음.)

TypeScript는 왜 필요할까 ?

JS 코드가 너무 지저분하다.

코드 스케일이 커지면서 코드 관리가 되지 않는다.

 

여러 사람들이 견고하지 않은 언어를 이용해서 협업을 하다보니 지저분한 코드들이 발생한다.

협업시 수많은 버그들이 발생된다. > 디버깅 환경이 빈약하다.

TypeScript의 장점 !

코드를 깔끔하게 정리할 수 있다.

어떻게 ? > Type을 명시함으로써 애매모호했던 코드들을 걷어낼 수 있다.

가독성 높아짐 > 퀄리티 높아짐 > 클린 코드에 가까워진 코드들을 생산할 수 있다 > 유지/보수가 쉬워진다. 선순환 !

TypeScript = JavaScript + Type Check !

TS 환경에 JS를 코딩하면 동작함.

JS 환경에 TS를 코딩하면 동작 안 함.

JS는 TS의 범주 안에 존재한다 !

Data Type Check 

JS는 변수는 종이컵과 같다 > 액체를 담기에는 편하지만 내용물이 무엇인지 정확하게 알 수가 없다.

TS의 변수는 투명페트병과 같다. > 내용물이 무엇인지 정확하게 보이고, 뚜껑을 닫음으로써 안전하게 보관할 수 있다.

 

- JS는 변수의 Data Type을 정확히 명시하지 않는다. ex) var -> 대입되는 값에 따라 변수의 type 달라진다

- TS는 변수에 Data Type을 명확하게 지정하여 안정성을 높여준다. ex) int, double -> 변수 type 고정

 

Data Type을 표기하면 좋은 점

- 객체 지향 프로그래밍의 특성을 지원한다.

- 클래스, 인터페이스, 컨스트럭터, 접근 지정자 등 객체 지향의 프로그래밍 특성을 지원

- TS를 이해하면 JS에 객체 지향 코드를 적용할 수 있다.


function Plus(a : number, b : number) {
  return a + b;
}

console.log(Plus(3, 5));

a, b의 type을 명시하여 해당 변수의 데이터 타입을 유추할 수 있다.

즉, a,b에 number가 아닌 다른 데이터 타입(문자열 등)이 들어오게 되면 바로 에러로 인식 > 에러를 발견할 수 있게 된다.

하지만, 만약 해당 함수가 js로 작성된 것이라면 a, b의 데이터 타입이 문자열로 들어오게 되어도 에러로 인식하지 않음.

우리가 의도한대로 작동하지 않아도 에러가 나지 않는다는 것 !

axios 통신 도중 delete에서 계속 400 에러 발생

요청 바디에 { clubName: '동아리명' } 형태로 보내야하는데 에러가 찍히지만 내가 원하는대로 잘 보내지길래 왜이러지 ? 싶었다

보내는 방식은 post에 요청 바디 보낼 때와 동일한 형태로 보냈음.

근데 저 에러에서 clubName 밑에 data: undefined가 조금 꺼림직했다.

지피티 최고 ㅠ

혹시나 하는 마음에 지피티에게 물어보니

DELETE 요청을 보낼 때도 요청 바디를 포함시킬 수 있다
>> 요청 바디를 포함 시키려면 data 옵션을 사용하라. 고 했다 !!!

 

그래서 아래의 형태로 보냈었던 요청을

const result = await API().delete('/admin/club', { clubName: name })

 

data 옵션을 사용해서 한번 더 감싸서 보내주니 !!!!

const result = await API().delete('/admin/club', {data: { clubName: name }})

 

반갑다 200아 ㅠ 해결완료 !

 

+ Recent posts