TIL - 잡다한 JavaScript 기본지식

sway3·2023년 5월 28일
0

TIL

목록 보기
3/4
post-thumbnail

오늘 새로 배운 내용을 간단하게 공부하여 적는 공간으로 잘못된 정보가 포함되어있을 수가 있습니다.

Udemy JS Clean Code 강의, 프로그래머스 코딩테스트 문제풀이 등을 공부하며 배웠던 내용들을 간단히 요약해서 적어보겠다.

실제 내 코드에도 적용시켜 보면서 확실히 배운 후, 각 항목에 대해 깊게 포스팅을 할 예정이다.

✅ JS Clean Code

전역 공간의 문제점

어떠한 변수를 전역 공간에 선언하였을 때, 그 변수는 전역 변수라고 불린다.

이렇게 선언된 전역 변수에는 모든 코드가 전역 변수를 참조하고 변경할 수 있는 '암묵적 결합' , 네임스페이스 오염, 변수 검색 속도 느림 등등 여러가지 문제점들이 존재한다.

가장 큰 문제점은 window, global 등을 통해 브라우저에서도 쉽게 접근하여 값을 변경할 수 있기 때문에 보안에 취약하다는 점이다. 특히나 var 로 선언한 전역 변수는 다른 스크립트 파일에서도 쉽게 접근이 가능하다.

const 와 let 을 사용하는 것만으로도 위의 문제점들이 여럿 해소되지만, 전역 공간에 변수를 선언하는 것을 최대한 지양할 필요가 있다.

또한, 즉시 실행함수 / 모듈 / Closure 등으로 스코프를 나누는 방법에 대해 고민해야할 필요가 있다고 한다.

✅ 임시 변수와 함수 표현식 사용

임시 변수 사용 자제하기

어떠한 서비스를 개발하는 과정에서 어떠한 기능을 변경 또는 추가해야할 상황이 있다. 이럴 때 각 함수에 임시 변수를 곳곳에 선언했다는 가정 하에, 변수에 할당된 값을 수정하는 등 변수들을 하나하나 확인해가며 코드를 수정하거나 추가해야하기 때문에 시간적인 비용이 정말 많이 든다.

또한, 하나의 기능만을 수행해야하는 함수에 기능을 추가하게 되며, 에러 발생 시 디버깅 과정이 굉장히 복잡해진다.

그렇기 때문에, 임시 변수를 선언하여 그 값을 같은 함수 내에서 다른 값으로 재할당하고 조작하는 과정을 최소화하고 함수를 작게 작게 쪼개어 특정 값을 바로 리턴하여 다른 함수내에서 사용하는 습관을 들이는 것이 좋다고 한다.

함수 표현식

함수를 정의할 때 선언식보다 표현식을 좀 더 사용해보도록 하자.

const 를 활용하여 함수 표현식으로 함수를 정의하는 경우, 호이스팅 (런타임 시 변수와 함수 선언이 코드 최상단으로 끌어올려지게 되는 과정) 으로 인해 에러를 잡아내기가 쉽다고 한다. 예상하지 못한 실행 결과 또한 방지할 수 있다고 한다.

✅ 프로그래머스 문제풀이

(에서 배운 메소드들)

1. split()

프로그래머스 lv0 - 특정 문자 제거하기 문제를 풀며 알게 된 메소드이다.

'String' 의 메소드이며, 인자의 값에 따라 문자열을 다양한 방법으로 나눌 수 있다.

let str = "Hellohello";
console.log(str.split('')); // ['H','e','l','l','o','h','e','l','l','o']
console.log(str.split(' ')); // ['Hellohello']
console.log(str.split('o')); // ['Hell','hell']

split() 의 매개변수는 'separator' 라고 불리운다. 빈 문자열을 separator 에 할당하게 될 경우, 문자열을 공백 포함하여 글자별로 쪼개어 배열로 리턴한다.

공백을 separator에 할당할 경우 문자열을 공백이 존재하는 구간마다 나누어 한 단어 한 단어를 배열에 담아 리턴한다.

이 외에도, 특정 문자열이나 숫자를 인자로 전달하면, 호출한 문자열에 인자가 존재할 경우 그 문자를 지우고 그 index 를 기준으로 문자열을 쪼갠다.

만약 separator 로 나눌 수 없는 문자열이라면, 그 문자열을 빈 배열에 담아 배열의 length 가 1인 배열을 리턴한다.

2. replace(), replaceAll()

프로그래머스 lv0 - 특정 문자 제거하기 문제를 풀며 알게 된 메소드이다.

replace(pattern, replacement)

replace() 는 문자열을 탐색하여 pattern (혹은 타겟 문자열) 에 할당된 값을 찾아내고, replacement 에 할당된 값으로 대체한다.

let str = "yoyoyo";
str.replace('o', 'i');  // yiyoyo

문자열에 존재하는 모든 pattern 에 대해 replacement 로 대체하지 않고, 첫번째로 발견되는 값만 대체하고 리턴하게 된다.

replaceAll(pattern, replacement)

그렇기 때문에 특정 patternreplacement 로 모두 대체하고 싶다면 다음과 같이 replaceAll() 을 사용하도록 하자.

let str = "yoyoyo";
str.replace('o', 'i');  // yiyiyi

replaceAll 을 특정제거 문자하기 문제에 적용할 수 있었다.

const solution = (my_string, letter) => my_string.replaceAll(letter, '');

위처럼 replaceAllreplacement 에 빈 문자열을 전달하면, pattern 을 문자열에서 제거하는 방식으로도 구현할 수 있다.

const solution = (my_string, letter) => [...my_string].filter(a => a !== letter).join('');

필자는 위처럼 filter, join, 스프레드 연산자 등으로 조금 복잡하게 구현하였는데, replaceAll 을 배운 후 훨씬 간단하게 문제를 해결할 수 있었다.

3. RegExp (정규표현식)

프로그래머스 lv0 - 모음 제거 문제에서 공부하게 되었다.

정규표현식은 리터럴 표기법으로 생성하여, 문자열에서 특정 내용을 찾아내는 데에 흔히 사용된다.

/regexp/i

시작기호와 종료기호는 '/' 이며, 뒤에 있는 i 는 flag 로, 개발자가 원하는대로 flag 을 사용할 수 있다. flag 의 종류는 다음과 같다.

  1. i - Ignore Case : 대소문자를 구별하지 않는다.
  2. g - Global: 패턴과 일치하는 첫 문자열을 발견해도 멈추지 않고 문자열 내의 모든 패턴을 검색한다.
  3. m - Multi Line: 문자열 내부에서 줄바꿈이 일어나도 멈추지 않고 문자열 내의 패턴 검색을 이어나간다.

앞서 공부한 replace, replaceAll 의 매개변수 pattern 에 정규표현식을 사용할 수도 있다.

/regexp/igm

위와 같이 flag 는 여러개를 중복해서 사용할 수 있다.

if (password.match(/[a-z]/) && password.match(/[A-Z]/))

회원가입을 할 때 사용자가 사용하고 싶은 비밀번호의 보안 수준을 평가할 때 사용할 수 있다. 위의 조건문은 password 문자열이 영어 대소문자로 이루어져있는지 평가하고 있다.

const solution = (my_string) => my_string.replace(/[aeiou]/g,'');

모음 제거 문제를 위와 같이 정규표현식을 사용해서 쉽게 풀 수 있었다.

정규표현식은 for 문 등의 작업을 간단히 대체해주지만, 무분별하게 사용한다면 가독성이 많이 떨어질 수 있으니 주의해야한다.

4. findIndex()

프로그래머스 lv0 - 첫 번째로 나오는 음수 문제를 풀고 알게된 메소드이다.

findIndex(callbackFn)

다음과 같이 콜백함수를 인자로 받아, 배열을 iterate 여 원소를 하나씩 콜백함수에 적용하여, 콜백함수가 true 를 반환했을 때 그 원소의 index 를 리턴한다. 만약 콜백함수가 배열의 모든 원소를 한번씩 거쳐갔다면, -1 을 리턴한다.

인자로 '값' 을 전달받아 그 값이 배열에 존재하는지 확인하고, 존재한다면 그 값의 index 를 리턴하는 indexOf() 와 혼동되지 않는 것이 중요하다.

findIndex() 는 콜백함수를, indexOf() 는 값을 인자로 받는다는 것을 기억하여 둘을 적재적소에 활용할 수 있도록 하자.

const solution = num_list => num_list.findIndex((neg) => neg < 0);

if-else, switch case 등으로 10줄 가까이 되던 코드를 한줄로 줄일 수 있었다.

5. map() 의 응용

프로그래머스 lv0 - 문자 반복 출력하기 문제를 풀며 map 을 좀 더 잘 활용할 수 있는 방법을 배웠다.

const solution = (my_string, n) => [...my_string].reduce((acc, cur) => [...acc, ...Array(n).fill(cur)], []).join('');

필자는 위처럼 reduce 를 사용하여 위의 문제를 좀 복잡하게 구현한 것 같다.

const solution = (my_string, n) => [...my_string].map(s => s.repeat(n)).join('');

map 함수의 인자는 콜백함수 인데, 그 콜백함수 안에 repeat 메소드를 사용하여 배열의 원소를 정말 쉽게 반복하고 새 배열로 리턴할 수 있었다.

콜백함수 내부에서 다른 메소드를 활용하는 방법도 지속적으로 생각하며 문제를 풀도록 하자.

6. slice() vs splice()

slice()
slice(start)
slice(start, end)

프로그래머스 lv0 - n 번째 원소부터 문제를 풀고 좀 더 공부하게 된 메소드들이다.

slice() 는 문자열, 배열의 start 번째 index의 원소부터 end-1 번째 원소까지만을 가져오고 싶을 때 사용할 수 있다.

인자를 생략하면 원래의 문자열/배열을 그대로 리턴하고, start 에만 값을 할당하면 start 번째 index 의 원소부터 문자열/배열의 끝까지 리턴한다.

splice(start)
splice(start, deleteCount)
splice(start, deleteCount, item1)
splice(start, deleteCount, item1, item2, itemN)

'huello'.splice(1, 0, 'u'); // hullo
'byebyemyblue'.splice(2, 2, 'hi'); // byhiyemyblue
[0, 1, 2, 3, 4].splice(5, 0, 5, 6, 7); // [0, 1, 2, 3, 4, 5, 6, 7]

splice() 는 deleteCount 의 값이 0 일 경우 문자열/배열의 start 번째 index 에 item1, item2, ... , itemN 을 넣고 원래 start 번째 인덱스부터 존재했던 원소들을 뒤로 밀어낸다.

deleteCount 가 1이거나 이상일 경우, start index 의 원소로부터 deleteCount 만큼의 원소를 item1, 2, ... N 으로 '대체' 한다.

replace(), replaceAll() 과 달리 원하는 index 위치에 원하는 원소를 밀어넣을 수도, 대체할 수도, 맨 뒤에 추가할 수 있다.

profile
병아리 개발자

0개의 댓글