코딩테스트 시간 별 전략
프론트엔드 코딩테스트에는 세가지 유형이 있다.
단순 알고리즘 테스트
- 그냥 알고리즘을 잘하면 된다!
- 프론트엔드에서 자주 나오는 유형은 아니다.
시간이 촉박한 구현 테스트 (3시간 ~ 4시간)
- 효율적인 구조를 신경쓰기보다 ‘빠르게 개발하는데’ 집중하라.
- 고득점을 위해서 효율적 구조를 빠르게 짜는 방법을 평소에 연습하라.(같은 동작이라면 효율적 구조가 더 높은 점수를 받을 것.)
시간이 널널한 구현 테스트 (1일 ~ 1주일)
- 현업에서 요구하는 정확한 방법으로 설계하라. (동작만 된다고 중요한게 아니다. 효율적 구조로 설계 못하면 광탈한다.)
- 웹 프론트엔드 설계 이론을 평소에 공부하라.
ESM
ESM이 모던 JavaScript의 표준으로 지정되면서 바닐라를 사용하는 코딩테스트에서도 ESM 사용을 요구하는 경우가 많아졌다.
1 | <script type="module" src="main.js"></script> |
script
태그에서 type
을 module
로 지정하면 된다.
1 | import { name, draw, reportArea, reportPerimeter } from './modules/square.js'; |
이제 알고 있는대로 esm의 import
와 export
문법을 사용하면 된다.
기존에는 script 태그의 순서대로 코드가 실행됐다면,
이제는 엔트리 포인트(index.js)를 중심으로 모듈 관계에 따라 코드가 실행된다.
여기서 주의할 점은 코딩테스트 환경에 맞춰 주소를 정확하게 기입해야한다.
Node.js 환경에 익숙한 사람들은 모듈을 불러올 때 보통 js
를 생략한다.
그러나 esm을 브라우저에서 사용하려면 확장자인 js
까지 ‘반드시’ 포함해야함을 잊지 말자.
Fetch API
1 | fetch('http://example.com/movies.json') |
1 | // Example POST method implementation: |
Fetch API는 바닐라 환경에서 XMLHttpRequest보다 현대적이고 유려한 방법을 제공한다.
기본적으로 GET Method
를 사용하며 Promise 패턴을 이용한다. (async 문법 가능)
아마 대부분의 코딩 테스트에서 application/json
형태로 request, reponse를 할 가능성이 높다.
fetch의 첫번째 인자는 주소를 입력하고, 두번째 인자에는 코딩테스트에서 요구하는 조건을 구성하면 된다.
Node 생성
DOM API를 읽기 전에 - 상속 관계 이해
- EventTarget ← Node ← Element ← HTMLElement
바닐라 JS를 하기 위해서는 DOM API의 상속 관계를 반드시 이해하기 바란다.
코딩 테스트는 라이브러리 개발이 아니므로 보통 HTMLElement
만을 다루게 된다.
다시말해, 부모 클래스인 EventTarget
, Node
, Element
타입의 메서드를 모두 골고루 알고 있어야한다.
공부하다보면 Node
클래스와 Element
클래스에서 비슷한 일을 수행하는 메서드들이 존재한다.
두 메서드의 표면적인 차이점을 느낄 수 없는 경우엔 Element
에서 정의한 메서드를 사용하라.
분명히 자식 클래스인 Element
클래스에서 새롭게 정의한 이유가 있을 것이다. (보통 더 유려하거나 편리하다.)
document.createElement() - Element
1 | let element = document.createElement(tagName[, options]); // HTML**Element |
document.createTextNode() - Text
1 | let text = document.createTextNode(data); // Text |
document.createAttribute() - Attr
1 | let attribute = document.createAttribute(name) |
Element 탐색
querySelector는 selector 문법을 이용해 상세 검색이 가능하다. (고급 기술)
단순 id, class, tagName으로 검색한다면 getElementBy{Id | ClassName | TagName}을 이용하자.
document.querySelector() - Element || null
1 | var element = document.querySelector(selectors); |
document.querySelectorAll() - NodeList
1 | var elementList = parentNode.querySelectorAll(selectors); |
document.getElementById() - Element || null
1 | var element = document.getElementById(id); |
document.getElementsByClassName() - HTMLCollection
1 | var elements = element.getElementsByClassName(names); |
document.getElementsByTagName() - HTMLCollection
1 | var elements = document.getElementsByTagName(name); |
Class 조작
element.classList - DOMTokenList
1 | const div = document.createElement('div'); |
classList
는 DOMTokenList
(유사 배열 객체)이며 class의 목록과 이를 수정하기 위한 모든 메서드를 지원한다.
Attribute 조작
element.attributes - NamedNodeMap
1 | let attrs = element.attributes; |
attributes
는 해시맵 형태의 NameNodeMap
객체이다.
orderedHashMap이기 때문에 index, key 두가지 방식으로 모두 접근 가능하다.
element.getAttribute() - string
1 | attrval = element.getAttribute(attributeName); |
element
attribute의 값을 반환한다.
element.setAttribute() - string
1 | value = element.setAttribute(name, value); |
element
의 attribute의 값을 설정한다.
element.getAttributeNames() - string[]
1 | attributeNames = element.getAttributeNames(); |
element
의 attribute 이름 배열을 반환한다.
element.removeAttribute()
1 | element.removeAttribute(attrName); |
element
의 attribute를 삭제한다.
Element 조작
element.innerHTML, element.outerHTML은 읽기 전용으로만 사용하길 권장
element.insert{something}()
1 | element.insertAdjacentHTML(where, data); |
HTML을 삽입하는게 아니라면 insertAdjacent 대신 element.append()
, element.prepend()
, element.after()
, element.before()
를 사용해도 동등하다.
element.remove()
1 | element.remove() |
DOM Tree에서 element
를 제거하고 완전히 소멸시켜버린다.
element.replaceWith()
1 | element.replaceWith(...nodes) |
element
자체의 레퍼런스를 완전히 다른 노드로 변경시킨다.
element.children - HTMLCollection
1 | children = element.children |
element
의 자식들을 반환한다. 이때 타입은 HTMLCollection(유사 배열 객체)이다.
- 첫번째 자식 element:
element.firstElementChild
- 마지막 자식 element:
element.lastElementChild
element.replaceChildren()
1 | element.replaceChildren(...nodesOrDOMStrings) |
element
의 자식들이 완전히 교체 된다.
element.childrenCount - number
1 | element.childElementCount |
element
의 자식들의 수를 반환한다.
element.nextElementSibling - Element
1 | let el = document.getElementById('div-01').nextElementSibling; |
같은 계층에 존재하는 element를 순회한다. 반대 방향으로는 element.previousElementSibling()
을 사용하면 된다.
만약 Element가 아닌 NodeList를 탐방하고 싶다면 node.nextSibling()`을 사용하라.
element.animate()
애니메이션 관련 CSS를 함께 학습해야한다. 이 링크를 참고하라.
노드(Node) 조작
비고
Element 클래스에서 비슷하게 할 수 있는 작업은 제외함
node.contains() - boolean
1 | node.contains(otherNode) |
otherNode
가 node
의 자식인지 평가한다.
node.removeChild() - Node
1 | child = node.removeChild(child); |
node
에서 child
를 삭제한다. 이때 삭제된 child
노드가 반환된다.
node.replaceChild() - Node
1 | oldChild = node.replaceChild(newChild, oldChild); |
node
의 자식 중에 oldChild
를 newChild
로 교체한다. 이때 교체된 oldChild
가 반환된다.
node.nodeName - string
1 | node.nodeName |
node
의 이름을 반환한다. 비슷한 프로퍼티로 node.NodeType`이 존재하는데 integer를 반환한다.
node.parentElement - Element
1 | node.parentElement |
node
의 parentElement
에 접근한다. 비슷한 프로퍼티로 node.parentNode는
Node` 타입을 반환한다.
node.textContent - string
1 | node.textContent = 'replace' |
node
의 textContent를 반환한다. 내용을 업데이트 하는 용도로 사용할 시 innerText
보다 빠르다고 알려져 있다.
HTMLElement 조작
element.focus()
호출한 element
를 포커싱 한다. 일부 이벤트는 포커싱 이후에 발생한다.
코딩 테스트에서는 주로 HTMLInputElement
에 대한 포커싱을 요구한다.
element.blur()
호출한 element
를 포커싱 해제한다.
element.click()
호출한 element
를 클릭한다. 버튼, 앵커의 경우 별도의 이벤트를 설정하지 않았다면 기본 동작이 실행된다.
element.style
element
의 CSS 스타일을 설정하는 property이다.
주의할점은 CSS는 보통 kebab-case
를 사용하지만 JS style은 lowerCamelCase
를 사용한다.
그 외에 API들
실제 코딩 테스트에서 유용한 메서드들 위주로 소개하였다.
허나 실제로 잘 사용하지 않더라도 많이 알고 있으면 나쁠게 없다.
Node, Element, HTMLElement 문서를 한번씩 읽어보자.
Event 조작
DOMContentLoaded
1 | window.addEventListener('DOMContentLoaded', (event) => { |
DOM이 안벽하게 로딩되었을때 발생하는 이벤트이다.
EventTarget.addEventListener()
1 | eventTarget.addEventListener(type, listener); |
이벤트를 수신하는 리스너를 추가할 수 있다.
이벤트 버블링과 캡처는 이 글을 읽어보길 추천한다.
- 주요 이벤트 (이벤트 목록)
- load (리소스가 로딩 되었을 때 - img 태그 등에서)
- focus (엘리먼트가 포커싱 인 되었을 때)
- blur (엘리먼트가 포커싱 아웃 되었을 때)
- submit (폼이 제출 되었을 때)
- reset (폼이 초기화 되었을 때)
- resize (다큐먼트 뷰가 리사이즈 되었을 때)
- scroll (엘리먼트가 스크롤 되었을 때)
- select (선택 가능한 영역에서 무엇인가 선택되었을 때)
- copy / cut (선택 가능한 영역에서 무엇인가 복사, 잘라내기 되었을 때)
- paste (수정 가능한 영역에서 무엇인가 붙여넣기 되었을 때)
- keydown / keyup / keypress (키가 눌렸을 때)
- mouseenter / mouseover / mousemove / mousedown / mouseup / mouseleave / mouseout (마우스 관련)
- click / dbclick / contextmenu (엘리먼트가 클릭 되었을 때 / 더블 클릭 / 오른쪽 클릭)
- drag / dragstart / dragend / dragenter / dragover / dragleave / drop (드래그&드롭 관련)
- touchstart / touchend / touchmove / touchcancel (터치 관련)
EventTarget.removeEventListener()
1 | eventTarget.removeEventListener(type, listener); |
이벤트를 삭제한다.
EventTarget.dispatchEvent()
1 | eventTarget.dispatchEvent(event) |
이벤트를 스크립트로 발생 시킬 수 있는 방법이다.
Scroll 조작
스크롤 동작을 이해하기 전에 보면 좋은 문서
- element 영역 관련 프로퍼티
- element 영역 관련 메서드
스크롤 프로퍼티
스크롤 메서드
- scroll() == scrollTo() - 엘리먼트의 절대적 위치를 기준으로 스크롤 발생
- scrollBy() - 엘리먼트의 상대적 위치를 기준으로 스크롤 발생
- scrollIntoView() - 엘리먼트가 속한 뷰를 기준으로 스크롤 발생
스크롤 제어 (overflow)
1 | .someting { |
visible
은 기본 값으로 컨테이너의 최대 길이를 초과해도 스크롤 하지 않고 그냥 보여준다.
hidden
은 컨테이너의 최대 길이를 초과한 영역은 보여주지 않는다. (스크롤 되지 않음)
scroll
은 컨테이너의 최대 길이를 초과한 것과 상관 없이 스크롤바를 항상 보여준다.
auto
는 컨테이너의 최대 길이를 초과했을 때만 스크롤바를 보여준다.
x
와 y
는 횡 스크롤, 종 스크롤을 의미한다.
스크롤 맨 위, 아래로 옮기기
1 | element.scrollTop = 0 // 맨 위로 |
채팅창 구현(메신저 개발)이 과제로 나온다면 반드시 필요한 스킬이다.
기타 디자인 요소
DotDotDot 처리 (Elipsis)
1 | .elipsis { |
width
값을 넘어가는 텍스트에 대하여 ・・・ 처리를 한다.
여러줄 Elipsis
1 | .elipsis-multiline { |
지정한 -webkit-line-clamp
만큼 텍스트를 출력하고 넘어가는 텍스트에 대해서는 ・・・ 처리를 한다.
이 때 height를 적절하게 설정해줘야 정상적으로 표시된다.
라인 수를 동적으로 지정하고 싶으면 css 팩토리 함수를 만들면 된다.
Image LazyLoad
1 | <img src="..." loading="lazy"> |
사용자 경험을 높이기 위해 lazy-loading을 요구할 수 있다.
주로 이미지 로딩에 대하여 이 기능을 요구하는데 loading="lazy"
라는 간단한 속성으로 구현할 수 있다.
저 태그가 있다고 무조건 lazy loading을 하는 것은 아니다.
브라우저마다 다르겠지만 만약 이전에 불러온적이 있다면 색인을 해뒀다 불러오는게 더 빠르다.
만약 lazy loading을 다시 보고 싶다면, Hard Reload(shfit+cntl/cmd+r)를 하라. (색인을 초기화 한다.)
또한, loading="lazy"
만 한다고 언제나 능사는 아니니, 각 상황별로 대처하기 위해 아래 문서를 읽어보길 바란다.
웹 성능 최적화를 위한 Image Lazy Loading 기법
Image Scroll Loading
1 | element.addEventListener('scroll', evt => { |
scroll이 최대로 내려왔을 때 새로운 Request를 보내는 방법이다.
<img loading="lazy">
와 함께 사용하면 시너지가 좋다.
W3Schools HowTo
W3Schools의 HowTo 항목에는 CSS와 VanillaJS를 조합하여 다양한 디자인 컴포넌트를 만드는 방법을 소개한다.
반응형 미디어 쿼리
기본 문법은 @media [media-type] and ([media-type-rule]) and ...
이다.
반응형 웹을 위해 필수로 미디어 쿼리에 대해 학습할 필요가 있다. 미디어 쿼리 학습
- 논리곱 (and) 예시
@media screen and (min-width: 400px) and (orientation: landscape)
→ 화면의 최소 폭이 400px이고 회전방향이 landscape일 경우
- 논리합 (,) 예시
@media screen and (min-width: 400px), screen and (orientation: landscape)
→ 화면의 최소 폭이 400px이거나 회전방향이 landscape일 경우
다크 모드 (Dark Mode)
1 | @media (prefers-color-scheme: dark) {} |
시험 전에 PC를 미리 다크모드로 설정해두면 확인하기 편리하다.