본문 바로가기

WINK-(Web & App)/React.js 스터디

[2025 1학기 React.js 스터디] 이서준 #2주차

반응형

코파는 블로깅 시작하겠습니다.

반복문

  • 주어진 조건이 충족되는 동안 특정 작업을 반복해서 수행
for(let i = 0; i < 5; i++){
	console.log(i); // 1 2 3 4 5
}

for(let i = 10; i > 0; i -= 2){
	console.log(i) // 10 8 6 4 2
}

continue & break

continue : 한 루프만 건너뜀

  • break: 루프 종료
for (let i = 0; i < 100; i++) {
	if (i % 3 === 0) continue; // 한 루프를 건너뜀
	if (i > 10) break; // 루프 종료
	console.log(i);
}

for … of문

  • 파이썬의 i in 배열과 같음
  • 배열 뿐 아니라 Iterable한 객체에도 사용 가능하다!
const myArray = [1, 2, 3, 4, 5];
for (const item of myArray){
	console.log(item);
}
  • 위에서 const item이 오류가 나지 않는 이유!
    • 블록 범위(block scope) 때문이다.
    • const는 새로운 블록(반복문 내부 실행 블록)에서 매번 새롭게 선언되면 문제없이 동작한다.
    • item은 각 반복마다 새로운 블록에서 선언되는 것이다.
    {
        const item = 1; // 첫 번째 반복
        console.log(item);
    }
    {
        const item = 2; // 두 번째 반복 (새로운 블록에서 새로 선언됨)
        console.log(item);
    }
    
    • item은 이렇게 다시 선언되기에, 기존 const item과 충돌없이 정상적으로 동작한다.

for … in문

  • 객체의 키들을 순서대로 반환
  • for of 문을 사용하고 싶다면, Object.entries() 사용하여 key-value쌍을 순회할 수 있음.Object.entries()는 객체를 [[key, value], [key, value], …] 형태의 배열로 변환한다.
  • const obj = { a: 1, b: 2, c: 3 }; for (const [key, value] of Object.entries(obj)) { console.log(key, value); } // for in과 같은 값 출력

forEach()

찾아보니, 배열이나 리스트를 반복할 때 사용하는 forEach() 메소드가 있어서 정리해보았다.

const array1 = ["a", "b", "c"];
array1.forEach((element) => console.log(element));
  • 매개변수로는 콜백함수가 들어간다. ( 배열의 각 요소에 대해 실행할 함수 )
  • undefined 아무것도 반환하지 않는다. ( map 과의 차이점 )
  • 반복 작업 수행의 용도로 사용된다!

while / do … while 문

  • while은 조건이 false면 실행 x ( 선 확인 후 조치 )
  • do … while은 조건이 false여도 최소 한번은 실행된다. ( 선 조치 후 확인 )
let x = 0;
while (x > 10){
	console.log(x);
}

do {
	console.log(x++);
} while (x < 10);

함수

함수도 값이다!

  • 변수, 상수에, 객체의 값이나 배열의 요소로, 다른 함수의 인자로 넣을 수 있음
  • const sub = function (x, y){ return x - y; console.log(sub(7, 2)); }

화살표 함수 ( arrow function )

  • function으로 정의한 함수와는 세부적으로는 기능이 다르다.
const mult = (x, y) => x * y;
console.log(mult(2, 7));

// or

const func = () => {
// 이런 식으로 작성
}

중괄호를 사용했다면, return 지시자로 결과값을 반환해주어야 한다.


HTML 요소 JS로 제어하기

HTML 요소들 선택하기

getElementsByTagName

태그 명으로 선택

document.getElementByTagName('section');
// section 태그 모두 선택

// 상수 or 변수로 저장 가능
const $listItems = document.getElementByTagName('li');
console.log($listItems);

getElementByClassName

클래스명으로 선택

document.getElementsByClassName('plant');
// class="plant" 모두 선택

getElementById

아이디로 선택

document.getElementById('sweets');
// id="sweets" 선택

HTML에서 id는 고유해야 해서 보통 중복이 되지 않는다.

그러나 브라우저에서는 오류를 내지 않는다.

  • 여러 개 있어도 **getElementById()**는 첫 번째 요소만 가지고 온다.

querySelctor

CSS 선택자로 선택 ( 태그, id, class )

  • 태그 ex) “div”
  • id ex) “#header”
  • class ex) “.box”
document.querySelector('section');
// 섹션 태그 선택 (첫번째)
document.querySelectorAll('section');
// 섹션 태그 모두 선택
document.querySelector('.plant > ul > .soldout');
// >(자식 선택자)를 사용하는 경우, 직계 자식을 선택함

“>” (자식 선택자)를 사용하지 않으면 어떻게 될까?

document.querySelector(".plant .soldout");

.plant 안에 .soldout이 어디에 있던지 첫 번째 것만 선택됨!

중첩된 구조라도 .menu 안에 있으면 상관 없다.

그러나 자식 선택자( > )를 사용하면 - 직계자식만 선택되기에 위의 예시처럼 타고 들어가야됨

children

자식 요소들 반환 ( 모든 직계 자식 요소 )

document
.querySelector('section');
.children

//첫번째 / 마지막 자식 요소 반환
const $firstUl = document.querySelector('ul');
$firstUl.firstElementChild; // 첫번째
$firstUl.lastElementChild; // 마지막

section 태그의 모든 직계 자식 요소들을 가져옴

🚨 텍스트 노드는 포함되지 않음

텍스트 노드를 포함하는 childNodes

const parent = document.querySelector(".parent");
console.log(parent.childNodes);  
// NodeList(5) [text, p, text, text, span]

childNodes를 사용하면 텍스트 노드(text)까지 포함된다.

또한 반환값이 children은 HTMLCollection, childNodes는 NodeList라는 차이점이 있다.

🚨 children을 사용할 때, HTMLCollection은 배열이 아니기 때문에, forEach 대신 for … of를 사용한다! ( for … of는 배열 뿐 아니라 iterable ( 반복 가능 )한 객체에도 사용 가능하다. )

요약

속성 반환값 포함 요소

.children HTMLCollection 요소(NodeType 1)만 포함
.childNodes NodeList 요소 + 텍스트 + 주석 등 모든 노드 포함

HTML 요소들 조작하기

textContext

요소의 텍스트 확인 및 수정

const $carrot = document
.querySelector('section li');

$carrot.textContext; // 텍스트 확인
$carrot.textContext = '제주당근'; // 텍스트 변경

classList

리스트 형태의 클래스 확인 & 수정

  • 배열과 유사함
$carrot.classList.remove('hidden');
$carrot.classList.add('organic');
$carrot.toggle('soldout');

classList.toggle()

클래스를 추가/제거하는 기능

toggle은 해당 클래스가 있으면 제거하고, 없으면 추가하는 기능을 한다!

classList.toggle(className, boolean) → 강제 추가/제거

  • true면 무조건 추가, false면 무조건 제거

getAttribute / setAttribute

요소 속성 반환 및 수정

**$hyperlink.setAttribute('href', '<https://naver.com>');
//이런식으로 링크 수정 가능**

이벤트

addEventListener

첫 번째 인자로 주어진 이벤트에, 두 번째 인자로 주어진 메서드( 콜백 함수 )의 동작을 부여

JS 이벤트 종류

 

UI 이벤트

load 웹 페이지의 로드가 완료되었을 때
unload 웹 페이지가 언로드 될 때 (새로운 페이지를 요청한 경우)
error 브라우저가 자바스크립트 오류를 만났거나 요청한 자원이 없는 경우
resize 브라우저의 창 크기를 조정했을 때
scroll 사용자가 페이지를 위아래로 스크롤 할 때

 

키보드 이벤트

keydown 사용자가 키를 처음 눌렀을 때
keyup 키를 땔 때
keypress 사용자가 눌렀던 키의 문자가 입력되었을 때

 

마우스 이벤트

click 사용자가 동일한 요소 위에서 마우스 버튼을 눌렀다 뗄 때
dbclick 두 번 눌렀다 뗄 때
mousedown 마우스를 누르고 있을 때
mouseup 눌렀던 마우스 버튼을 뗄 때
mousemove 마우스를 움직였을 때
mouseover 요소 위로 마우스를 움직였을 때
mouseout 요소 바깥으로 마우스를 움직였을 때

 

포커스 이벤트

focus 요소가 포커스를 얻었을 때
blur 요소가 포커스를 잃었을 때

 

onClick과 addEventListener의 차이

  1. 이벤트 덮어쓰기 vs 이벤트 누적addEventListener를 사용할 경우 여러 이벤트를 추가하더라도 누적되어 모든 이벤트가 동작된다.
  2. onclick은 이벤트를 여러 개 적용하는 것이 불가능하다. 만일 onclick 이벤트 핸들러를 이미 사용한 상태에서 새로운 onclick 이벤트를 추가한다면 이후에 추가된 이벤트가 기존의 이벤트를 덮어쓴다.
  3. 브라우저 호환성addEventListener는 오래된 브라우저를 지원해야 할 경우 사용할 수 없다.
  4. onclick 이벤트는 모든 브라우저에서 호환이 가능하다.
  5. 버블링 / 캡처링세 번째 파라미터가 true일 경우 캡처링을 사용하고, false일 경우 버블링을 사용한다.이것을 사용하여 더욱 세밀한 제어가 가능하다.
  6. clickEvent.addEventListener('click', 이벤트 리스너, 버블링 / 캡쳐링);
  7. ( 캡처링 - 자식 → 부모로 / 버블링 - 부모 → 자식으로 )
  8. addEventListener는 세 번째 파라미터로 이벤트가 발생할 때 버블링으로 작동될 지, 캡쳐링으로 작동될 지 지정할 수 있다. ( onclick은 기본적으로 버블링 방식 )

최종 프로젝트

defer 스크립트

<script defer src="./script.js"></script>

쉽게 말하면 js파일이 실행되기 전에 html 요소를 다 화면에 불러온 다음에 js 코드가 실행되도록 앞에 defer를 붙여주는 것이다.

이렇게 하지 않으면, 이 아래 요소들이 로드가 되기도 전에 이 js 코드가 동작하여 아직 존재하지 않는 요소를 조작할 가능성이 있음

변수명에 $(달러) 기호를 왜 ?

식별자에 사용되는 $ 기호는 해당 변수가 DOM Node라는 것을 의미한다.

과거 jQuery를 사용할 떄 $(node)로 node를 검색했던 것에서 이어져 현재까지도 DOM Node를 표현하기 위해 변수명에 달러($)를 붙여준다.

const $todos = document.querySelector(".totos");

달러 기호 사용이 싫다면 변수명 뒤에 Element를 붙여 명확하게 할 수 있다.

const todosElement = document.querySelector(".todos");

addEventListener는 이벤트를 실행하는 것이 아니라 등록해주는 거다

조금 멍청한 생각이었지만,

for (let i = 0; i < $currLis.length; i++) {
  const $li = $currLis[i];
  $li.addEventListener("mouseenter", () => {
    $currProgBar.style.width = 200 * i + "px";
  });
  $li.addEventListener("mouseleave", () => {
    $currProgBar.style.width = 0;
  });
}

이 코드에서 왜 마우스를 올렸을 때 i가 막 바뀌는 건지 모르겠다는 생각을 했다.

이는 addEventListener 자체를 이벤트를 실행하는 것이라고 생각해서 생긴 문제였다.

addEventListener는 이벤트를 실행하는 것이 아니라 등록해주는 함수이다.

for문을 살펴보면, addEventListener를 사용해서 li마다 mouseenter, mouseleave 이벤트에 관한 이벤트리스너를 등록해주었다. 그래서 맞는 인덱스에 커서를 올려놓으면, 이벤트함수가 실행되어서progressbar를 바꿔주는 것이었다.

요약하자면 li마다 이벤트를 등록해주었다 생각하면 된다.

toggle(토글)

$menuBtn.addEventListener("click", () => {
  $menuBtn.classList.toggle("on");
  $headerNav.classList.toggle("active");
});

document.querySelector("body").addEventListener("click", () => {
  $menuBtn.classList.remove("on");
  $headerNav.classList.remove("active");
});

토글 목록을 누르면 안에 목차가 나오고, 밖을 누르면 토글 목록이 사라지게 하는 것을 구현하는 코드이다. 그러나 위 코드로 구현하면 눌러도 토글 목록이 나오지 않는다. 왜그럴까???!?!?!?

이유

이유는 이벤트 버블링 때문이었다. header__menu-btn 클래스가 header 안에 있고, header가 body 안에 있고 이런 식으로 싸여 있어서 header__menu-btn에서 클릭 이벤트가 발생하면 header, body도 이벤트가 실행되어 눌렀을 때 toggle이 실행되고, 바로 remove가 실행되어서 생기는 문제였다.

해결

해결 방법은, 클릭 이벤트가 발생할 때, 매개변수로 이벤트 객체를 넣어주어, e.stopPropagation() 메서드를 선언해 버블링을 막아주면 된다. ( 이렇게 하면 되는거였어요 )

$menuBtn.addEventListener("click", (e) => {
  $menuBtn.classList.toggle("on");
  $headerNav.classList.toggle("active");
  e.stopPropagation();
});

document.querySelector("body").addEventListener("click", () => {
  $menuBtn.classList.remove("on");
  $headerNav.classList.remove("active");
});

아 잘된다 ㅋㅋ

아 빡세다 그래도 다했어요

많이 배웠습니다

스터디는 다음에 가겠습니다

 

반응형