프로그래머스 데브코스, 국비지원교육, 코딩부트캠프
실습을 하면서 node.js를 배워가는 중이다. 그 중에서 정리해두면 좋을 것 같다고 생각한 내용들을 오늘 TIL에 정리해 보았다.
GET API 실습을 하던 중 url에 포함되는 파라미터 값을 response로 띄워보는 내용이 있었다.
❗여기서 req.params
란!
: /product/:id
의 라우터 경로에서 req.params.id
를 이용하여 id의 값을 받아올 수 있다.
처음에는 라우터 경로에 숫자를 입력했으니 숫자로 받아오겠지 하는 생각을 가지고 있었다.
그런데 실제 실행을 해보니 위처럼 문자열로 받아오고 있었다.
실제로 검색을 해보니 req.params
는 무조건 문자열로 받아온다고 한다. (오늘도 고맙습니다 스택 오버플로우...) (근데 나도 왜 당연히 숫자로만 받아올 거라고 생각했지)
나는 이 문자열로 받아온 값에 약간의 연산을 더해주고 싶었다.
req.params
는 무조건 문자열로 값을 받아오고... 일반적으로 문자열에서 불가능한 연산인 -
연산을 진행하면 과연 어떻게 될까? 오류가 발생할까?
정답은 아니오다.
실행 후 결과값을 보면 내가 입력한 파라미터 값인 20에서 10을 뺀 10이 정상적으로 반환되고 있다. 심지어 문자열도 아니다.
어떻게 이런 일이 발생할 수 있을까? 그건 바로 자바스크립트의 묵시적/암시적 형변환(자동 형변환)
이라는 특징 때문이다.
자바스크립트는 동적 타입 언어다. int
나 String
같은 타입을 지정하여 변수를 선언하는 게 아니라 let
, var
, const
처럼 타입을 지정하지 않고 변수를 선언하고 값에 따라 타입이 지정되는 방식이다.
let num = 1 // type : number
let str = 'bar' // type : string
let bool = true // type : boolean
타입의 변환이 자유롭기 때문에 아까 전 작성했던 예시처럼 일반적으로는 불가능한 문자열과 숫자 간 연산도 문자열을 숫자로 변환하여 수행해준다.
이걸 바로 묵시적/암시적 형변환(implicit coercion)
이라고 한다.
let num1 = '23'
let num2 = '12'
let num3 = 10
num1 + num2 = '2312' // 기본적으로 더하기 연산은 문자열은 문자열끼리 진행
num1 - num2 = 11 // 두 문자열이 숫자 타입으로 변환하여 연산이 진행
num1 * num2 = 276 // 두 문자열이 숫자 타입으로 변환하여 연산이 진행
num1 + num3 = 2310 // 문자열과 숫자 간 더하기 연산은 숫자가 문자열로 변환되어 연산
num1 - num3 = 13 // 문자열이 숫자 타입으로 변환되어 연산이 진행
즉, 정리하자면 특정한 타입이 기대되는 자리에 기대하는 것과 다른 타입이 오면 자동으로 타입을 변환해주는 것이라고 보면 된다.
참고로 타입을 명시해줘야 하는 자바 같은 경우에는 문자열과 숫자 간 연산(-, *, / 등)을 진행하려고 할 때 위와 같은 에러가 발생한다.
자바스크립트에는 암시적 형변환
만 존재하는 것은 아니다. 내가 직접 형변환을 시킬 수도 있다. 그게 바로 명시적 형변환(explicit coercion)
이다.
내가 원하지 않는 방향으로 형변환이 이루어지는 경우가 있을 수도 있다. 이럴 때에는 내가 직접 타입을 변환할 필요가 있다. 형변환을 하는 함수는 아래와 같다.
Number()
: 숫자로 변환parseInt()
: 정수로 변환parseFloat()
: 소수로 변환String()
: 문자열로 변환Object()
: 객체로 변환위 예시에서는 정수로 변환하기 위해 parseInt
를 사용하였다.
실행을 하면 위 사진처럼 정수로 형변환이 되어서 나타나는 걸 볼 수 있다.
자바스크립트의 타입을 더 알고 싶다면 ⬇️ 아래의 링크로 들어가보자!
그리고 배열과 객체를 더 편리하게 선언할 수 있는 비구조화 할당에 대해서도 가볍게 짚고 넘어갔다.
비구조화 할당
이란 배열이나 객체의 값을 해체하여 그 값을 변수에 각각 담아 사용하는 자바스크립트 표현식이다. 해당 표현식은 ES6 이후로 새롭게 생겼다.
비구조화 할당이 생기기 이전, 즉 ES6 이전에는 배열의 값을 꺼내기 위해서는 하나씩 지정해줘야만 했다.
const numList = [10, 100, 1000];
const num1 = numList[0];
const num2 = numList[1];
const num3 = numList[2];
console.log(num1);
console.log(num2);
console.log(num3);
직접 배열의 인덱스에 하나씩 저장해야하기 때문에 귀찮다는 단점이 있다.
이 단점을 해결해주는 것이 바로 배열의 비구조화 할당
이다! ES6 이후 위 코드와 동일하게 돌아가는 코드는 아래와 같다.
const [num1, num2, num3] = [10, 100, 1000];
// 이미 선언된 배열도 각각 대응되는 변수에 저장 가능
// const numList = [10, 100, 1000];
// const [num1, num2, num3] = numList;
console.log(num1);
console.log(num2);
console.log(num3);
각 배열의 인덱스에 접근할 필요도 없고 훨씬 더 코드가 보기 편해졌다는 걸 알 수 있다.
객체의 비구조화 할당
도 배열의 비구조화 할당과 동일한 구성이다.
ES6 이전에는 객체를 선언하고 각 객체의 값을 변수에 저장해주어야 했다.
const numList = {
num1: '10',
num2: '100',
num3: '1000'
}
const ten = numList.num1;
const hundred = numList.num2;
const thousand = numList.num3;
console.log(ten);
console.log(hundred);
console.log(thousand);
각 객체의 value 값을 하나씩 변수에 저장해주어야 하기 때문에 마찬가지로 코드가 길어진다는 단점이 있다.
하지만 ES6 이후 비구조화 할당을 이용하면 아래와 같이 바꿀 수 있다.
const {num1, num2, num3} = {
num1: '10',
num2: '100',
num3: '1000'
}
/*
const numList = {
num1: '10',
num2: '100',
num3: '1000'
}
{num1, num2, num3} = numList
마찬가지로 이미 선언된 객체도 저장 가능
*/
console.log(num1);
console.log(num2);
console.log(num3);
여기서 유의해야 할 점은 객체의 key
값과 변수명
을 동일하게 지정해주어야 한다.
Map은 key와 value 쌍으로 이루어진 자료구조다. key를 통해 데이터에 쉽게 접근할 수 있는 장점이 있다.
맵의 key 값을 중복해서 1로 넣었을 때 이후에 저장한 값만 들어간 걸 확인할 수 있다.
3.맵은 iterator 특징을 가진다.
iterator는 배열 등과 같은 내부 요소를 순회하는 객체다. 맵은 내부 요소를 순회할 수 있는 객체적인 특징을 가지고 있다.
new Map()
: 빈 맵을 생성
map.set(key, value)
: key를 이용해 value를 저장
map.get(key)
: key에 해당하는 값을 반환합니다. key가 존재하지 않으면 undefined를 반환
map.has(key)
: key가 존재하면 true, 존재하지 않으면 false를 반환
map.delete(key)
: key에 해당하는 값을 삭제
map.clear()
: 맵 안의 모든 요소를 제거
map.size
: 요소의 개수를 반환
map.keys()
: 각 요소의 키를 모은 반복 가능한(iterable) 객체 반환
map.values()
: 각 요소의 값을 모은 이터러블 객체 반환
map.entries()
: 요소의 [키, 값]의 쌍을 모은 이터러블 객체 반환
참고 자료 : Map과 Set
최근에는 실습을 위주로 강의를 듣고 있다. 아직 초반부여서 그런지 내용이 어렵지는 않지만 오늘 정리한 것처럼 더 딥하게 공부해야 하는 건 점점 늘어나고 있는 것 같다.