1. let - url param 생성 함수 만들기


let은 ‘재할당’, 즉 이미 할당이 이루어진 변수에 다시 다른 값을 할당할 수 있는 변수 선언 방식입니다. 실무에서는 주로 자주 변경을 해야 하는 경우 또는 넘어온 데이터를 변형, 재가공하는 과정에서 임시로 저장할 필요가 있을 때에 활용하게 됩니다. let으로 선언한 변수에는 기존에 할당한 값과 데이터 타입이 같은지 여부와 관계 없이 어떤 데이터 타입의 값도 재할당할 수 있습니다.

let을 좀 더 자세히 알아보기에 앞서 간단한 예제를 먼저 살펴볼까 합니다. 다음 네 가지 파라미터를 받아 실제로 검색 페이지로 이동할 수 있는 URL을 만들어 봅시다.

  • 검색어(query)
  • 검색기간유형(period): y(1년), 6m(6개월), m(한 달), w(한 주), d(하루)
  • 시작일(startDate): YYYYMMDDHHmmss
  • 마감일(endDate): YYYYMMDDHHmmss

1. 기본 코드

1
2
3
4
5
6
7
8
const buildUrl = (query, period, startDate, endDate) => {
let url = 'https://search.daum.net/search?w=tot&q=' + encodeURI(query)
if (period) url += '&period=' + period
if (startDate) url += '&sd=' + startDate
if (endDate) url += '&ed=' + endDate
return url
}
const newUrl = buildUrl('자바스크립트', 'm', '20200626000000', '202007260000000')
  • 1행에서는 buildUrl이라는 변경 불가능한 변수를 선언하고, 여기에 새로운 익명의 화살표함수를 할당했습니다. buildUrl 함수는 query, period, startDate, endDate를 파라미터로 받습니다.
  • 이후 8행에서 buildUrl 함수를 호출하였습니다.
  • 2행에서 변경 가능한 변수 url을 선언하고, 여기에 https://search.daum.net/search?w=tot&q=javascript를 저장했습니다. encodeURI는 검색어가 한글 등 브라우저가 인식할 수 없는 글자들로 이루어진 경우 이를 브라우저가 인식할 수 있는 글자로 바꾸어 줍니다.
  • 3행의 period 값이 비어있지 않으므로 이제 url 값은 https://search.daum.net/search?w=tot&q=javascript&period=w가 됩니다.
  • 같은 방식으로 4행 및 5행을 거치면, 최종적으로 url에는 https://search.daum.net/search?w=tot&q=javascript&period=m&sd=202006262000000&ed=202007262000000가 담기게 됩니다.
  • 6행에서 최종값을 반환해주면 함수가 종료되고, 반환된 url 값이 8행의 newUrl에 담기게 됩니다.
  • 9행에서는 브라우저의 href 값을 newUrl로 교체해 줌으로써 다음의 검색화면으로 이동하게 됩니다.

예제의 2행에서 선언한 변수 url의 값은 5행까지 각 행을 거치면서 문자열의 내용이 점차 증가했습니다. 사실 우리는 url 변수에 다른 문자열을 ‘추가’하라는 명령을 내렸지만, 실제로는 기존 내용과 추가된 내용을 합쳐서 ‘완전히 새로운’ 문자열을 만들고, 그렇게 만들어진 새 문자열을 url 변수에 ‘재할당’ 하는 식으로 동작합니다. 이처럼 let은 재할당이 필요한 경우에 유용한 변수 선언 방식입니다.

위 예제는 let을 소개하기 위해 마련했지만, 실은 더 나은 방안이 많이 있습니다.

2. 배열 활용

가장 먼저 생각할 수 있는 방법은 배열을 이용하는 것입니다.

1
2
3
4
5
6
7
8
const buildUrl = (query, period, startDate, endDate) => {
const queries = ['w=tot', 'q=' + encodeURI(query)]
if (period) queries.push('period=' + period)
if (startDate) queries.push('sd=' + startDate)
if (endDate) queries.push('ed=' + endDate)
return 'https://search.daum.net/search?' + queries.join('&')
}
const newUrl = buildUrl('자바스크립트', 'm', '20200626000000', '202007260000000')

배열과 join 메서드를 사용했습니다. ‘&’를 입력하는 횟수가 적으므로 상대적으로 실수할 가능성이 줄어들었습니다. 다만 여전히 개발자가 직접 반복 입력해야 하는 내용이 많이 보입니다. 가능한 모든 수단을 동원하여 반복을 최소화 하고 싶네요.
다시 한 번 코드를 살펴봅시다. 함수 파라미터를 query 대신 q, startDate 대신 sd, endDate 대신 ed로 바꾼다면 뭔가 가능할 것도 같습니다. 일단 해보죠.

3. 객체와 map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const buildUrl = queries => {
const searchParams = Object.entries(queries)
searchParams.unshift(['w', 'tot'])
const searchParamsString = searchParams
.map(([key, value]) => {
if (key === 'q') return key + '=' + encodeURI(value)
return key + '=' + value
})
.join('&')
return 'https://search.daum.net/search?' + searchParamsString
}
const newUrl = buildUrl({
q: '자바스크립트',
period: 'm',
sd: '20200626000000',
ed: '202007260000000',
})

고민 끝에 아예 buildUrl 함수가 인자를 객체 하나만 받도록 고쳐보았습니다. 객체의 프로퍼티 키(key)값은 ‘query’, ‘startDate’, ‘endDate’ 대신 실제 url에 적용해야 하는 q, sd, ed로 명칭을 변경하였습니다. 이 객체를 다시 Object.entries 메서드에 대입함으로써 [key, value] 쌍으로 이루어진 배열로 전환하고, 반환된 내용을 searchParams에 할당했습니다.
4행에서는 배열 메서드인 map을 이용하여 문자열을 조합하였습니다. 앞의 (2)에 비해 사용자가 직접 제어하는 내용은 더 줄었고, 대신 자바스크립트 엔진이 처리하도록 위임한 부분이 늘었습니다. map 메서드 내부의 콜백함수에서는 첫 번째 인자를 바로 해체하여 사용하였습니다. 사용자가 직접 제어하는 내용이 줄어들 수록 실수 가능성도 함께 줄어들고, 보다 프로그래밍이 지향하는 방향에 가까워 집니다.

4. URLSearchParams

1
2
3
4
5
6
7
8
9
10
11
12
13
const buildUrl = queries => {
const searchParams = new URLSearchParams('w=tot')
Object.entries(queries).forEach(([key, value]) => {
searchParams.append(key, value)
})
return 'https://search.daum.net/search?' + searchParams.toString()
}
const newUrl = buildUrl({
q: '자바스크립트',
period: 'm',
sd: '20200626000000',
ed: '202007260000000',
})

이번에는 URLSearchParams 라는 window 내장 메서드를 이용했습니다. 이 방법은 각 키와 값 사이에 ‘=’을 입력할 필요가 없습니다. 뿐만 아니라 인코딩을 신경 쓰지 않아도 됩니다. 명시적으로 ‘URLSearchParams’를 다루는 것임을 표기하고 있어 다른 개발자들이 이 함수가 어떤 식으로 동작할 것인지를 예측하기도 쉽습니다.
단점이라면, IExplorer에서는 URLSearchParams을 지원하지 않으니 코드가 실제 사용될 환경을 고려할 필요가 있습니다.

마치며

  • let을 다룬다고 해놓고 이상한 내용이 덕지덕지 붙었습니다. 앞으로도 계속해서 이렇게 제멋대로 이상하게 흘러가는 글을 써보고자 합니다.
  • let에 대해서는 다음 포스트에서 이어서 소개할 것입니다.
  • 위 방안들 외에 다른 더 좋은 방법이 있다면 댓글로 알려주세요!