객체?
다양한 타입의 값을 하나의 단위로 구성한 복합적인 자료구조이다. 객체는 프로퍼티의 집합이며, 프로퍼티는 키와 값으로 구성된다.
객체 프로퍼티 접근
하는 방법은 2가지가 있다.
const person = {
firstName : "Yu-Na",
"last-name" : "park",
1 : 10
};
person.firstName // Yu-na
person["last-name"] // park
원시값 vs 객체
함수?
입력을 받아 출력을 내보내는 일련의 과정을 문으로 구현하고 코드 블록으로 감싸서 하나의
실행 단위로 정의한 것 이다. 함수는 객체이지만 일반 객체와 달리 함수는 호출할 수 있고, 함수 객체의 고유한 프로퍼티를 가진다.
즉시 실행 함수
는 단 한번만 호출되며 다시 호출할 수 없다. 함수의 이름이 없는 익명 함수를 사용하는 것이 일반적이다.
let result = (function () {
let a = 4;
let b = 8;
return a * b;
})();
재귀 함수
함수가 자기 자신을 호출한다. 재귀 함수는 자신을 무한 재귀 호출하기 때문에 재귀 호출을 멈출 수 있는 탈출 조건을 반드시 만들어야 한다.
function recusion(n) {
if(n < 0) return;
console.log(n);
recusion(n - 1);
}
recusion(10);
중첩 함수
함수 내부에 정의된 함수를 중첩 함수 또는 내부 함수라 한다. 그리고 중첩 함수를 포함하는 함수는 외부 함수라 부른다. 중첩 함수는 스코프와 클로저에 깊은 관련이 있다.
function outer(n) {
let x = 1;
function inner() {
let y = 2;
console.log(x + y);
}
inner();
}
outer();
recusion(10);
콜백 함수
함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수이다.
function repeat(n, callback) {
for(let i=0; i<n; i++){
callback(i);
}
}
const log = function(i) {
console.log(i);
}
repeat(5, log);
브라우저의 렌더링 과정
렌더링이란 HTML, CSS, javascript로 작성된 문서를 파싱하여 브라우저에 시각적으로 출력하는 것이다.
DOM(Document Object Model)
HTML 문서의 계층적 구조와 정보를 표현하며 이를 제어할 수 있는 API이자, 프로퍼티와 메서드를 제공하는 트리 자료 구조다.
노드 객체 타입
DOM은 노드 객체들로 구성된 트리 자료구조를 말하며, DOM 트리라고도 불린다.
문서 노드
요소 노드
어트리뷰트 노드
텍스트 노드
타입이 중요!
DOM API - 요소 노드 취득
할 수 있는 방법은 크게 4가지로 나뉜다.
HTMLCollection vs NodeList
HTMLCollection과 NodeList를 구분하는 중요한 특징은 노드 객체의 상태 변화를 실시간으로 반영하는 살아 있는 객체라는 점이다. -> iterable 객체
// HTMLCollection
<style>
.red {
color: red;
}
.blue {
color: blue;
}
</style>
<body>
<ul id="fruits">
<li class="red">Apple</li>
<li class="red">Banana</li>
<li class="red">Orange</li>
</ul>
<script>
// class 값이 'red'인 요소 노드를 모두 탐색하여 HTMLCollection 객체에 담아 반환한다.
const $elems = document.getElementsByClassName("red");
// 이 시점에 HTMLCollection 객체에는 3개의 요소 노드가 담겨 있다.
console.log($elems); // HTMLCollection(3) [li.red, li.red, li.red]
// HTMLCollection 객체의 모든 요소의 class 값을 blue로 변경한다.
for (let i = 0; i < $elems.length; i++) {
$elems[i].className = "blue";
}
// HTMLCollection 객체의 요소가 3개에서 1개로 변경되었다.
console.log($elems);
// 유사 배열 객체이면서 이터러블인 HTMLCollection을 배열로 변환하여 순회
[...$elems].forEach((elem) => (elem.className = "blue"));
</script>
</body>
노드 탐색
DOM 조작
innerHTML 프로퍼티 : Element.prototype.innerHTML 프로퍼티는 요소 노드의 HTML 마크업을 취득하거나 변경하며 HTML 마크업을 문자열(string)로 반환한다. 텍스트만 가져오는 Node.prototype.textContent 프로퍼티도 있다.
요소 노드의 innerHTML 프로퍼티에 문자열을 할당하면 요소 노드의 모든 자식 노드가 제거되고 할당한 문자열에 포함되어 있는 HTML 마크업이 파싱되어 요소 노드의 자식 노드로 DOM에 반영된다. innerHTML 프로퍼티는 복잡하지 않은 요소를 새롭게 추가할 때 유용하지만 기존 요소를 제거하지 않으면서 위치를 지정해 새로운 요소를 삽입해야 할 때는 사용하지 않는 것이 좋다.
insertAdjacentHTML 메서드 : Element.prototype.insertAdjacentHTML 메서드는 기존 요소를 제거하지 않으면서 위치를 지정해 새로운 요소를 삽입한다. 두 번째 인수로 전달한 HTML 마크업 문자열(DOMString)을 파싱하고 그 결과로 생성된 노드를 첫 번째 인수로 전달한 위치(position)에 삽입하여 DOM에 반영한다. 첫 번째 인수로 전달할 수 있는 문자열은 beforebegin(태그앞), afterbegin(텍스트앞), beforeend(텍스트뒤), afterend(태그뒤)있다. insertAdjacentHTML 메서드는 기존 요소에는 영향을 주지 않고 새롭게 삽입될 요소만을 파싱하여 자식 요소로 추가하므로 innerHTML 프로퍼티보다 효율적이고 빠르다.
노드 생성 및 추가, 노드 삽입 : 요소 노드 생성은 Document.prototype.createElement(tagName) 메서드를 사용하며 텍스트 노드 생성은 Document.prototype.createTextNode(text) 메서드를 사용한다. 텍스트 노드를 요소 노드의 자식 노드로 추가하기 위해서는 Node.prototype.appendChild(childNode)메서드를 사용한다.
let $container = document.getElementById('container');
let $div = document.createElement('div');
let $text = document.createTextNode('hi');
$div.appendChild($text);
$container.appendChild($div);
어트리뷰트 노드
HTML 요소의 시작 태그(start/opening tag)에 어트리뷰트 이름=“어트리뷰트 값” 형식으로 정의한다.
글로벌 어트리뷰트(id, class, style, title, lang, tabindex, draggable, hidden 등)와 이벤트 핸
들러 어트리뷰트(onclick, onchange, onfocus, onblur, oninput, onkeypress, onkeydown, onkeyup, onmouseover, onsubmit, onload 등)는 모든 HTML 요소에서 공통적으로 사용할 수 있지만 특정 HTML 요소에만 한정적으로 사용 가능한 어트리뷰트도 있다.
요소 노드의 모든 어트리뷰트 노드는 요소 노드의 Element.prototype.attributes 프로퍼티로 취득할 수 있다.
인라인 스타일 조작
HTMLElement.prototype.style을 사용해 인라인 스타일(inline style)을 취득, 추가, 변경 가능하다. ex) background-color backgroundColor
클래스 조작(className)
Element.prototype.className 프로퍼티는 HTML 요소의 class 어트리뷰트 값을 취득하거나 변경한다.
클래스 조작(classList)
Element.prototype.classList 프로퍼티는 class 어트리뷰트의 정보를 담은 DOMTokenList 객체 반환한다.
이벤트 타입
이벤트 핸들러 등록
<body>
<bitton onclick="sayHi('park')"></button>
<script>
function sayHi(name) {
console.log(`Hi! ${name}`);
}
</script>
</body>
<body>
<bitton>Click me!</button>
<script>
const $btn = document.querySelector('button');
// 이벤트 핸들러 프로퍼니에 이벤트 핸들러를 바인딩
$btn.onclick = function () {
console.log('button click');
}
</script>
</body>
이벤트 핸들러 제거
EventTarget.prototype.removeEventListener 메서드를 사용해 addEventListener 메서드로 등록한 이벤트 핸들러를 제거한다. 단, addEventListener 메서드에 전달한 인수와 removeEventListener 메서드에 전달한 인수가 동일하지 않으면 이벤트 핸들러가 제거되지 않는다.
공통 프로퍼티
이벤트 전파
는 이벤트 객체가 전파되는 방향에 따라 3단계로 구분할 수 있다.
<html>
<body>
<ul id="fruits">
<li id="apple">Apple</li>
<li id="banana">Banana</li>
<li id="orange">Orange</li>
</ul>
</body>
<script>
const $fruits = document.getElementById("fruits");
$fruits.addEventListener("click", (e) => {
console.log(`이벤트 단계 : ${e.eventPhase}`);
console.log(`이벤트 타깃 : ${e.target}`);
console.log(`현재 타깃 : ${e.currentTarget}`);
});
</script>
</html>
이벤트는 캡처링과 버블링을 통해 전파되지만, 버블링을 통해 전파되지 않은 이벤트들도 있다. 해당 이벤트들은 버블링이 발생하지 않기 때문에 이벤트 타깃의 상위 요소에서 캐치하려면 캡처링 단계의 이벤트를 캐치해야한다.
이벤트 위임
은 여러 개의 하위 DOM 요소에 각각 이벤트 핸들러를 대신 하나의 상위 DOM 요소에 이벤트 핸들러를 등록하는 방법을 말한다. 이벤트 위임을 통해 상위 DOM 요소에 이벤트 핸들러를 등록하면 여러 개의 하위 DOM 요소에 이벤트 핸들러를 등록할 필요가 없다. 또한 동적으로 하위 DOM 요소를 추가하더라도 일일이 추가된 DOM 요소에 이벤트 핸들러를 등록할 필요가 없다.