CEOS 1주차 (DOM, 이벤트흐름, 클로저&스코프)

·2024년 9월 6일

CEOS 1주차 과제에서 나온 질문들
조금 더 깊게 DEEP DIVE하기 위해 블로그에 적어 보려고 한다

1️⃣ DOM은 무엇인가요?

✨ window 객체 구조

자바스크립트의 최상위 객체, 전역 객체, 모든 객체가 소속된 객체로
브라우저를 대변하고 이를 제어할 수 있는 메서드 제공

✨ DOM의 개념

Document Object Model
HTML을 객체의 형태로 바꾸어서 구조화된 모델이며, HTML에 접근하기 위한 일종의 인터페이스이다. 이때 DOM은 nodes와 objects로 문서를 표현하며, Javascript를 이용해 이를 수정할 수 있다.
즉, 단순한 텍스트 파일을 브라우저에 렌더링하기 위해서는
브라우저가 이해할 수 있는 구조로 메모리에 올려야 하는데,
이때의 구조가 바로 DOM에 해당한다

👉 HTML tag들을 브라우저가 이해할 수 있는 객체 형태로 구성한 것,
구성된 html tag들을 브라우저의 이해를 위해 DOM tree 형태로 변경한 것

🌟노드(Node): 계층적 단위로 정보 저장

<html>
	<head>
		<title>제목입니다.</title>
	</head>
	<body>
		<a href="">링크입니다.</a>
		<p>단락입니다.</p>
	</body>
</html>

✨ DOM API

웹 문서의 동적 변경을 위해
프로그래밍 언어가 자신에게 접근하고 수정할 수 있는 방법을 제공하는 것,

🌟 API: 프로그램을 사용하기 위한 명령어들의 집합
DOMAPI모음

✨ BOM

Browser Object Model
자바스크립트를 이용하여 브라우저의 정보에 접근하거나
브라우저의 여러 기능을 제어하기 위해 사용하는 객체 모델,
js가 브라우저와 소통하기 위해 만들어진 모델

✨ BOM 종류

  • location: url 주소에 대한 정보 제공
  • document: 현재 문서에 대한 정보
  • navigator: 브라우저의 정보를 제공, 주로 호환성 문제를 위해 사용
  • history: 브라우저의 방문 기록 정보 제공
  • screen : 브라우저의 외부 환경에 대한 정보를 제공

2️⃣ 이벤트 흐름 제어(버블링 & 캡처링)이 무엇인가요?

✨ Event란?

웹 브라우저가 알려주는 HTML 요소에 대한 사건의 발생
즉, 사용자와 웹페이지의 상호작용을 브라우저가 감지하는 것
ex) 사용자가 버튼을 클릭, 웹페이지의 로드, 사용자가 스크롤을 내리는 것 스크롤 등

✨ 이벤트 루프와 동시성

자바스크립트는 single-thread 언어로 한 번에 하나의 작업만 수행할 수 있다.

🌟 thread란?
👉 프로세스 내에서 실제로 작업을 수행하는 주체

하지만, 실제로 동작하는 웹사이트는 많은 작업이 동시에 처리되는데,
이처럼 자바스크립트 동시성을 지원하는 것이 바로 이벤트 루프이다

🔆 자바스크립트 엔진

자바스크립트 엔진은 2개의 영역을 가지고 있다.

  1. call stack (호출 스택)
    소스 코드가 실행되면,
    요청된 작업은 콜스텍에 push (어떤 함수를 실행-> 해당 함수를 stack 맨 위로)
    종료 후에는 pop(return or 종료하면 스택 맨 위에서 꺼내는 작업) 이 이루어진다.
    이때 단 하나의 Call stack을 사용하기 때문에 task가 종료하기 전까지는 어떤 task도 수행될 수 없다.

  2. heap
    객체가 저장하는 메모리 공간이며,
    콜스택의 요소인 실행 컨텍스트가 힙에 저장된 객체를 참조해 값을 가져오는 것,
    자바스크립트 객체가 저장되는 공간

✨ 동시성 처리 (비동기 처리)

🔆 동기 vs 비동기

  • 동기(Synchronous) : 요청을 보낸 후 응답을 받아야 다음 동작이 이루어지는 방식, 어떠한 태스크를 처리할 동안 나머지는 대기
  • 비동기(Asynchronous) : 코드가 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 것

🔄 Event Loop

비동기 함수들을 적절한 시점에 실행시키는 관리자로 끊임없이 돌아가는 자바스크립트 내 루프
call stack이 비어있고, Task Queue에 대기 중인 함수가 있다면,
Event Loop가 FIFO 방식으로 Task Queue에 대기 중인 함수를 Call Stack으로 이동, 즉 자바스크립트의 동시성을 지원해주는 것이 바로 이벤트 루프인 것이다!!

🌟 Event Queue (Task Queue)
비동기 처리 함수의 콜백 함수, 비동기식 이벤트 핸들러, Timer 함수의 콜백 함수가 보관되는 영역으로 Event Loop에 의해 Call Stack이 비어졌을 때 순차적으로 Call Stack으로 이동되어 실행된다,
즉 비동기 함수의 콜백 함수 또는 이벤트 핸들러가 일시적으로 보관되는 공간이다

🌟 Web API
브라우저에서 제공하는 API 모음으로 비동기적으로 실행되는 작업들을 전담하여 처리,
Web API에는 동기적으로 처리되는 것과 비동기적으로 처리되는 것(setTimeout, fetch, addEventListner)이 모두 있음

🔄 동작 방식

  1. 자바스크립트의 비동기 자바스크립트 코드를 브라우저 Web APIs에 맡긴다.
  2. 작업이 끝난 결과를 콜백 함수 형태로 큐(Event Queue)에 넣는다.
  3. Call Stack이 비어있고, Event Queue 작업 처리 준비가 되면,
    호출 스택에 넣어 마무리 작업을 진행한다.

이를 위해 Event Loop는
all Stack 내에서 현재 실행중인 task가 있는지,
Event Queue에 task 가 있는지Web API

반복해서 확인한다.

✨ Event Handler 등록

Event Handler: 이벤트가 발생하면 실행되는 함수

🌟 addEventListenr

특정 이벤트 발생을 감지하는 역할을 수행

EventTarget(대상요소).addEventListener('eventType', functionName, [,useCapture]);

🔆 eventType: 대상요소에 바인딩될 이벤트를 나타내는 문자열
🔆 funtionName: 이벤트 발생 시에 호출될 함수명 or 함수 그 자체
🔆 useCapture: capture 사용여부 (true: capturing, false: bubbling)

🌟 이벤트 핸들러 프로퍼티 방식

element.onclick = funtion(e) {....}

🔆 이벤트 핸들러 프로퍼티에 하나의 이벤트 핸들러만 바인딩할 수 있다.
🔆 addEventListener 보다 먼저 실행된다.

✨ Event Object

이벤트를 발생시킨 요소와 발생한 이벤트에 대한 정보를 제공하는 이벤트 객체이다
ex) 'click'이벤트가 발생했다면, 마우스 포인트가 어디에 있는지
'keydown' 이벤트가 발생했다면 어떤 키가 눌렸는지

🔆 동적으로 생성된다.
🔆 이벤트 핸들러의 인자로 암묵적으로 전달된다.

🌟 Event Property

event.
🔆 type : 이벤트 타입
🔆 target : 실제로 이벤트를 발생시킨 요소
🔆 currentTarget : 이벤트를 감지한 요소(listner가 부착된 요소)

🌟 Event Method

🔆 e.preventDefault() : 이벤트의 기본 동작 중단
🔆 e.stopPropagation() : 이벤트가 상위 요소로 전파되지 않도록 중단

✨ Event 흐름이란?

html의 문서들은 태그 안의 태그의 형식으로 계층적으로 이루어져 있다.
이 경우 한 요소에 이벤트가 발생할 때 연쇄적으로 이벤트 흐름이 나타날 수 있다
이를 이벤트 전파 현상(event propagantion)이라고 하며,
전파 방향에 따라 버블링과 캡처링으로 구분할 수 있다

🌟 버블링

자식 요소에서 발생한 이벤트가 바깥 부모 요소로 전파되는 것으로 최상위 요소까지 버블링되며, 리스너가 부착된 요소에서 이벤트 발생을 감지한다.

🌟 버블링 예시 코드

<body>
 <div class="one">
   <div class="two">
     <div class="three">
     </div>
   </div>
 </div>
</body>
let divs = document.querySelectorAll('div');
divs.forEach(function(div){
	div.addEventListener('click', function(e){
    	console.log(e.currentTarget.className);
    });
});
  1. 가장 안쪽의 <p> 선택, <p> 에 할당된 <onClick> 핸들러 동작
  2. 바깥의 <div> 에 할당된 핸들러 동작
  3. 바깥의 <form>에 할당된 핸들러 동작
  4. <document> 객체를 만날 때까지 각 요소에 할당된 <onClick> 핸들러 동작

🌟 캡처링(Capturing)

> 이벤트가 부모 요소로부터 시작하여 안쪽 자식 요소까지 도달하는 것으로, 최상위 요소인 body 태그에서 해당 태그를 찾아 내려간다.

🌟 캡처링 예시 코드

<body>
  <div class="one">
    <div class="two">
      <div class="three">
      </div>
    </div>
  </div>
</body>
let divs = document.querySelectorAll('div');
divs.forEach(function(div){
	div.addEventListener(
      'click', 
      function(e){
    	console.log(e.currentTarget.className);
      }),  
      true // default 값은 false입니다.
  );
});

addEventListener()의 마지막인자로 true를 전달하면 이벤트 캡처링이 발생한다. 따라서 three를 선택했을 때, one -> twe -> three 순으로 로그가 찍힌다.

🔆 event.stopPropagation() 으로 이벤트 버블링, 캡처링을 막을 수 있다.

✨ 이벤트 위임

하위 요소에 각각 이벤트를 붙이지 않고, 상위 요소에서 하위 요소의 이벤트들을 제어하는 방식, 합리적인 메모리 사용과 이벤트 관리, 메모리 누수를 막을 수 있다.

<ul id="menu">
  <li><button id="file">파일</button></li>
  <li><button id="edit">편집</button></li>
  <li><button id="view">보기</button></li>
</ul>
document.getElementById("file").addEventListener("click", function(e) {
  // 파일 메뉴 동작
});
document.getElementById("edit").addEventListener("click", function(e) {
  // 편집 메뉴 동작
});
document.getElementById("view").addEventListener("click", function(e) {
  // 보기 메뉴 동작
});

해당 코드를 이벤트 위임하면,

document.getElementById("menu").addEventListener("click", function(e) {
  var target = e.target;
  if (target.id === "file") {
    // 파일 메뉴 동작
  } else if (target.id === "edit") {
    // 편집 메뉴 동작
  } else if (target.id === "view") {
    // 보기 메뉴 동작
  }
});

참고

3️⃣ 클로저와 스코프가 무엇인가요?

✨ 스코프

사전적인 의미로 '범위'를 뜻하며, JavaScript로 함수를 작성할 시, 중괄호 {}를 이용하여 함수의 범위를 작성한다.
즉, 코드가 영향을 미치는 범위, 변수의 유효 범위 등으로 정의할 수 있다.

🌟 스코프의 개념

선언된 변수에 대해서 접근할 수 있는 유효한 범위이다.
계층적 구조를 가지기 때문에 하위 스코프 -> 상위 스코프 접근은 허용되지만, 반대는 허용하지 않는다.

✨ 스코프의 구분

🌟 동작에 따른 구분

정적 스코프(렉시컬 스코프)

특정 구역 내에서 사용하는 스코프로 컴파일 타임에 결정되고 변하지 않음

function name() {
  var name = 'Hyein';
}

function getName() {
  console.log(name);
}

getName(); // undefined

위의 예시에서, getName함수는 name에 접근할 수 없으므로 undefined가 출력된다.

🔆 동적 스코프

동적 스코프의 선언은 런타임 도중에 실행 컨텍스트나 호출 컨텍스트에 의해서 결정된다

var name = 'Ewha'

function name() {
  var name = 'Hyein';
  getName();
}

function getName() {
  console.log(name);
}

getName(); // hyein

🌟 레벨에 따른 구분

🔆 전역 스코프

전역 스코프는 전역으로 선언된 변수에 대해 접근과 조작이 가능한 유효 범위를 의미한다

let global = 'Global!'; // 전역 변수

function scope() {
  let local = 'Local!'; // 지역 변수
  console.log(global);
};

scope(); // Global!
console.log(local); // local is not defined

🔆 지역 스코프

변수가 함수 혹은 블록 내에서 접근이 가능한 유효 범위를 의미한다

🌙 함수 레벨 스코프

var로 선언되었으며, 함수 내에서 유효한 범위를 의미한다

function hi(name) {
	if (name) {
		var greeting = 'Hello ' + name;
	}
	console.log(greeting);
}

hi('Hyein'); // Hello Hyein 
🌙 블록 레벨 스코프

블록 내에서 유효한 범위를 가지면 letconst로 선언된 변수, 함수들은 블록 레벨 스코프가 된다.

function hi(name) {
	if (name) {
		var greeting = 'Hello ' + name;
	}
	console.log(greeting);
}

hi('Hyein'); // greeting is not defined

✨ 클로저

함수와 그 함수가 선언됐을 때 렉시컬 환경(어휘적 환경)과의 조합
즉, 내부 함수에서 외부 함수의 범위에 대한 접근을 제공하는 것, 함수의 지칭과 함수가 선언된 환경과의 관계 개념

🌟 클로저의 특징

스코프를 이용하여 변수의 접근 범위를 폐쇄하는 것이다

  • 외부 함수 스코프에서 내부 함수 스코프로의 접근 불가
  • 내부 함수에서는 외부 함수 스코프에서 선언된 변수에 접근 가능

🌟 클로저의 장점

  1. 전역 변수 사용의 최소화 : 의도치 않게 접근하는 상황을 막을 수 있다.
  2. 데이터 보존 가능 : 외부 함수의 실행이 끝나더라도 외부 함수 내 변수를 사용할 수 있다.
  3. 모듈화를 통한 코드 재사용에 편리: 클로저 함수를 변수에 각각 할당하면 각자 독립적으로 값을 사용하고 보존이 가능하다
  4. 정보의 접근 제한: 클로저 모듈 패턴을 사용해 객체에 담아 여러 개의 함수를 리턴하도록 만들어 정보의 접근을 제한할 수 있다(캡슐화)
profile
new blog: https://hae0-02ni.tistory.com/

0개의 댓글