[프론트엔드 인터뷰]FE-Study 3주차 1회

event bubbling에 대해 설명하세요.

이벤트 버블링은 특정 화면 요소에서 이벤트가 발생했을 때 해당 이벤트가 더 상위의 화면 요소들로 전달되어 가는 특성을 의미합니다.

image

상위의 화면 요소란? HTML 요소는 기본적으로 트리 구조를 갖습니다. 여기서는 트리 구조상으로 한 단계 위에 있는 요소를 상위 요소라고 하며 body 태그를 최상위 요소라고 부르겠습니다.

<body>
  <div class="one">
    <div class="two">
      <div class="three"></div>
    </div>
  </div>
</body>
var divs = document.querySelectorAll('div')
divs.forEach(function(div) {
  div.addEventListener('click', logEvent)
})

function logEvent(event) {
  console.log(event.currentTarget.className)
}

위 코드는 세 개의 div 태그에 모두 클릭 이벤트를 등록하고 클릭했을 때 logEvent 함수를 실행시키는 코드입니다. 여기서 위 그림대로 최하위 div 태그

를 클릭하면 아래와 같은 결과가 실행됩니다.

three
two
one

div 태그 한 개만 클릭했을 뿐인데 왜 3개의 이벤트가 발생되는 걸까요? 그 이유는 브라우저가 이벤트를 감지하는 방식 때문입니다.

브라우저는 특정 화면 요소에서 이벤트가 발생했을 때 그 이벤트를 최상위에 있는 화면 요소까지 이벤트를 전파시깁니다. 따라서, 클래스 명 three => two => one 순서로 div 태그에 등록된 이벤트들이 실행됩니다. 마찬가지로 two 클래스를 갖는 두번째 태그를 클릭했다면 two => one 순으로 클릭 이벤트가 발생합니다.

여기서 주의해야 할 점은 각 태그마다 이벤트가 등록되어 있기 때문에 상위 요소로 이벤트가 전달되는 것을 확인할 수 있습니다. 만약 이벤트가 특정 div 태그에만 달려 있다면 위와 같은 동작 결과는 확인할 수 없습니다.

이와 같은 하위에서 상위 요소로의 이벤트 전파 방식을 이벤트 버블링이라고 합니다.

event capture

이벤트 캡쳐는 이벤트 버블링과 반대 방향으로 진행되는 이벤트 전파 방식입니다.

image

위 그림처럼 특정 이벤트가 발생했을 때 최상위 요소인 body 태그에서 해당 클릭한 태그를 찾아 내려갑니다.

var divs = document.querySelectorAll('div')
divs.forEach(function(div) {
  div.addEventListener('click', logEvent)
  capture: true // 기본값은 false
})

function logEvent(event) {
  console.log(event.currentTarget.className)
}

event.stopPropagation()

그냥 내가 선택한 해당 요소의 이벤트만 신경쓰고 싶다고 하시면 event.stopPropagation()를 사용하시면 됩니다.

function logEvent(event) {
  event.stopPropagation()
}

이벤트 내용은 캡틴 판교님의 블로그를 참고했습니다.

attribute와 property의 차이점은 무엇인가요?

attribute는 HTML 마크업에 정의되지만 property는 DOM는 정의됩니다. 차이점을 설명하기 위해 HTML에 다음 텍스트 필드가 있다고 가정해 봅시다. <input type:"text" value="Hello">

const input = document.querySelector('input')
console.log(input.getAttribute('value')) // Hello
console.log(input.value) // Hello

그러나 input 텍스트 필드에 “World!”를 추가하면 이렇게 될것입니다.

console.log(input.getAttribute('value')) // Hello
console.log(input.value) // Hello World!

내장 javaScript 객체를 확장하는 것이 좋은 생각이 아닌 이유는 무엇인가요?

내장/네이티브 JavaScript 객체를 확장한다는 것은 prototype에 속성/함수를 추가한다는 것을 의미합니다. 이것은 처음에는 좋은 생각처럼 보일 수 있지만 실제로는 위험합니다. 결국 prototype을 수정하는 것이기 때문에 표준 객체에 비표준 기능을 추가하는 것은 지향할 만한 방법도 아니고 안티패턴입니다.

내장 객체 확장의 좋은 사례는 폴리필을 만들때입니다.

Polyfill

폴리필은 개발자가 특정 기능이 지원되지 않는 브라우저를 위해 사용할 수 있는 코드 조각이나 플로그인을 말합니다.

if (!String.prototype.includes) {
  String.prototype.includes = function(search, start) {
    'use strict'
    if (typeof start !== 'number') {
      start = 0
    }
    if (start + search.length > this.length) {
      return false
    } else {
      return this.indexOf(search, start) !== -1
    }
  }
}

내장객체의 종류는

  • Object
  • Function
  • Array
  • String
  • Number
  • Boolean
  • Date
  • Math
  • RegExp
  • Symbol
  • Error

document load 이벤트와 document DOMContentLoaded 이벤트의 차이점은 무엇인가요?

DOMContentLoaded는 브라우저가 HTML을 전부 읽고 DOM 트리를 완성하는 즉시 발생합니다. 이미지 파일(<img>)이나 스타일시트 등의 기타 자원은 기다리지 않습니다.

document load는 HTML로 DOM트리를 만드는게 완성되었을 뿐만 아니라 이미지, 스타일시트 같은 외부 자원도 모두 불러오는 것이 끝났을 떄 발생합니다.

beforeunload/unload는 사용자가 페이지를 떠날 때 발생합니다.

어디에 사용할 수 있나요?

DOMContentLoaded는 DOM이 준비된 것을 확인한 후 원하는 DOM 노드를 찾아 핸들러를 등록해 인터페이스를 초기화할 때 사용합니다.

document.addEventListener('DOMContentLoaded', () => {
  console.log('원하는 코드 적기')
})

load는 이미지 사이즈를 확인할 때 등, 외부 자원이 로드된 후이기 때문에 스타일이 적용된 상태이므로 화면에 뿌려지는 요소의 실제 크기를 확인할 수 있습니다.

document.addEventListener('load', () => {
  console.log('원하는 코드 적기')
})

beforeunload는 사용자가 사이트를 떠나려 할 때, 변경되지 않은 사항들을 저장했는지 확인시켜줄 때 사용합니다.

unload는 사용자가 진짜 떠나기 전에 사용자 분석 정보를 담은 통계자료를 전송하고자 할때 사용합니다.

==와 ===의 차이점은 무엇인가요?

==는 추상 동등 연산자이고 ===는 완전 동등 연산자입니다. ==연산자는 타입 변환이 필요한 경우 타입 변환을 한 후에 동등한지 비교할 것입니다. === 연산자는 타입 변환을 하지 않으므로 두 값이 같은 타입이 아닌 경우 === 는 false를 반환합니다. ==를 사용하면 다음과 같은 좋지 않은 상황이 발생할 수 있습니다.

1 == '1' // true
1 == [1] // true
1 == true // true
0 == '' // true
0 == '0' // true
0 == false // true

편의상 null과 undefined를 비교할 때를 제외하곤, == 연산자를 절대 사용하지 않는게 좋습니다. a == null은 a가 null 또는 undefined면 true를 반환합니다.

var a = null
console.log(a == null) // true
console.log(a == undefined) // true