import sys
input = sys.stdin.readline

N, K = map(int, input().split())
coins = []
count = 0

coins = [int(input()) for _ in range(N)]

coins.sort(reverse=True)

for coin in coins:
  count += K // coin
  K = K % coin
  if K == 0: break

print(count)

동전이 오름차순으로 입력되는데 우리는 필요한 동전 개수의 최솟값을 출력해야하기 때문에 내림차순 정렬을 한다.

 

1. K원을 큰 동전부터 나눈 후 몫을 count 한다.

ex) 4200원이면 4200 // 1000 > 동전 4개 카운트

2. K원을 큰 동전으로 나눈 나머지를 다시 반복해서 나눌 수 있도록 K에 넣는다.

ex) 4200 % 1000 > 200원

 

남은 200원으로 반복문 수행, 남은 돈이 0이 될 때까지 반복

 

 

'코테 > 백준' 카테고리의 다른 글

백준 10816 숫자 카드 2 - 파이썬  (0) 2024.06.25
백준 1920 수 찾기 - 파이썬  (0) 2024.06.25
백준 11399번 ATM - 파이썬  (0) 2024.06.25
백준 1931 회의실 배정 : 파이썬  (0) 2024.06.25
1157번: 단어공부 - 파이썬  (0) 2024.05.14

 

import sys
input = sys.stdin.readline

N = int(input())
time = []

for i in range(N):
  start, end = map(int,input().split())
  time.append((start, end))

time.sort(key=lambda x : (x[1], x[0]))

cnt = 1
end = time[0][1]

for i in range(1, N):
  if time[i][0] >= end:
    end = time[i][1]
    cnt += 1

print(cnt)

회의가 빨리 끝나게 되면 남은 회의 시간이 많아서 더 많은 회의를 할 수 있다.

그래서 빨리 끝나는 순서대로 회의 시간을 정렬한다.

time.sort(key=lambda x : (x[1], x[0]))

두 번째 값(x[1])을 먼저, 첫 번째 값(x[0])을 그 다음 기준으로 삼아 정렬하는 방식

x[1]이 회의 종료시간이기 때문에 회의가 빨리 끝나는 순서대로 정렬되게 됨

(이 과정에서 요소 자체는 변하지 않고, 정렬 기준만 달라지는 것)


정렬된 회의시간을 반복해서 다음 회의 시작 시간 >= 이전 회의 끝나는 시간 을 만족할 때 해당 회의를 진행하도록 한다.

for i in range(1, N):
  if time[i][0] >= end:
    end = time[i][1]
    cnt += 1

이미 회의가 빨리 끝나는대로 정렬되어 있기 때문에 회의 시간이 겹치지 않도록 조건만 걸어준다.

겹치지 않을 때, 해당 회의 끝나는 시간을 end에 넣어서 다음 조건을 실행할 수 있게하고

회의 횟수 cnt를 더한다

'코테 > 백준' 카테고리의 다른 글

백준 10816 숫자 카드 2 - 파이썬  (0) 2024.06.25
백준 1920 수 찾기 - 파이썬  (0) 2024.06.25
백준 11399번 ATM - 파이썬  (0) 2024.06.25
백준 11047 동전 0 - 파이썬  (0) 2024.06.25
1157번: 단어공부 - 파이썬  (0) 2024.05.14
word = input().upper() # 입력 단어
unique_word = list(set(word)) # 입력된 문자의 중복을 제거한 후 리스트 형으로 변환

cnt = [] # 각 문자의 개수를 담을 리스트

for i in unique_word:
  cnt.append(word.count(i)) # word 안 문자의 개수를 구함
  
if cnt.count(max(cnt)) > 1: # 제일 많이 사용된 알파벳의 갯수가 중복되면
  print('?') # ? 출력
else: # 제일 많이 사용된 알파벳의 갯수가 중복되지 않으면
  print(unique_word[cnt.index(max(cnt))]) # 최댓값의 인덱스를 구한 후 word_list 인덱스 번호로 대입해서 출력
# word_list와 cnt의 인덱스는 매칭되는 관계임

반복문에서 unique_word를 순회하면서 cnt에 개수를 담았으므로 두 리스트 인덱스 관계를 생각해서 풀었다.

cnt의 최댓값의 인덱스 번호를 가지고 unique_word의 인덱스 번호에 대입하면 해당 인덱스의 값인 알파벳이 나온다.

해당 알파벳이 최대로 사용된 알파벳인 것

개헷갈린다 하

'코테 > 백준' 카테고리의 다른 글

백준 10816 숫자 카드 2 - 파이썬  (0) 2024.06.25
백준 1920 수 찾기 - 파이썬  (0) 2024.06.25
백준 11399번 ATM - 파이썬  (0) 2024.06.25
백준 11047 동전 0 - 파이썬  (0) 2024.06.25
백준 1931 회의실 배정 : 파이썬  (0) 2024.06.25
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에서 새롭게 도입된 비교 문법 (객체 비교에는 적합하지 않음.)

+ Recent posts