단어 찾기 기능 ctrl + F
=> 과제 제출 전 한번 더 확인하기
불필요하게 classList.add만 사용하지 않고, classList.remove도 응용하기
변수명, 함수명 네이밍 유의
truthy와 falsy에 정확한 개념 확립하고 조건문 더 간결히 사용하기
불필요한 공백 주의
innerHTML, innerText 그리고 textContent의 차이를 알고 그에 맞게 사용하기
변수명 정확한 네이밍 (매개변수로 전달하는 변수 또한)
이벤트 핸들러 함수명 ( handle + DOM element 이름 + 이벤트 명) => handleChoiceClick
올바른 세미콜론의 사용(함수 선언문, if문, 반복문에서 사용x) 과 따옴표 뒤에 공백 추가하기
상수 네이밍 => 가독성 위해, 위치 최상단에 배치하기
git 추가를 할 때 commit 은 추가한 내용에 대해 적어 줄 것
동적으로 코드를 짠다는 것은 무슨뜻일까?
=> 자바스크립트 상에서
함수 네이밍 동사 + 명사
좀 잘 지키자.. 뭘 행하는지부터 알려주는 거니까 동사가 앞으로
이벤트를 추가하기 위한 함수는 handle + 명사 + 동사
로 네이밍
classList
를 통한 스타일 변경이 아닌, 직접적으로 style을 변경할 경우 => 인라인 스타일
이 적용됨
인라인 스타일의 경우 우선 순위가 높아서 스타일 적용에 있어 문제가 발생될 가능성이 있으므로 지양
css와 자바스크립트 각자의 역할이 분명하게 존재하기에 서로 섞이지 않게 주의할 것
//직접적인 style 수정은 지양❌
document.querySelector(".quiz").style.display = "block";
// 옳은 예시 ✅
choices.classList.add("hide");
!important
를 붙인 속성HTML
에서 style
을 직접 지정한 속성#id
로 지정한 속성.클래스
, :추상클래스
로 지정한 속성태그이름
으로 지정한 속성=> index
접근을 통한 classList를 통해 변경가능
const choices = document.querySelectorAll(".choice"); => 4개의 <li>
// 수정 전 지양하는 방식❌
if (choicesLength === 2) {
choices[0].innerHTML = choice[0] ;
choices[1].innerHTML = choice[1];
choices[2].style.display = "none";
choices[3].style.display = "none";
} else {
choices[2].style.display = "flex";
choices[3].style.display = "flex";
choices[0].innerHTML = choice[0];
choices[1].innerHTML = choice[1];
choices[2].innerHTML = choice[2];
choices[3].innerHTML = choice[3];
}
//밑은 수정한 코드 ✅
// index를 이용하여 classList 사용
if (choicesLength === 2) {
choices[0].textContent = choice[0] ;
choices[1].textContent = choice[1];
choices[2].classList.remove("show");
choices[3].classList.remove("show");
choices[2].classList.add("hide");
choices[3].classList.add("hide");
} else {
choices[2].classList.add("flex");
choices[3].classList.add("flex");
choices[0].textContent = choice[0];
choices[1].textContent = choice[1];
choices[2].textContent = choice[2];
choices[3].textContent = choice[3];
}
// 위의 코드는 해당 조건이 안될 시에 버그가 생길 수 있으므로
// 밑에 코드처럼 동적으로 코드를 짜서
// hide, show와 같은 class를 부여하지 않고 필요한 DOM 요소를 추가할 수 있어 더 효율적
function appendQuizChoices() {
data[dataIndex].choices.forEach(function(Choice) {
const quizChoiceDiv = document.createElement("div");
const quizChoicesP = document.createElement("p");
let pTagText = document.createTextNode(Choice);
quizChoicesP.appendChild(pTagText);
quizChoiceDiv.appendChild(quizChoicesP);
quizChoiceDiv.classList.add("quiz-choices");
$quizChoices.appendChild(quizChoiceDiv);
});
}
변수명 함수명의 경우 항상 내가 아닌 다른 분들이 코드를 확인했을 때
해당 변수명, 함수명을 통해 어떤 것인지, 어떤 역할을 하는 것인지 (무엇을 하는지) 인지할 수 있는 네이밍이 중요
=> 매개변수로 전달하는 인자 또한 역할에 따라 네이밍
// 의미없는 네이밍 ❌
showQuiz(data);
function showQuiz(text) { 코드 내용 };
// text 보단 quizList 같은 변수명이 더 적절 ✅
function showQuiz(quizList) { 코드 내용 };
.
// 지양하는 방식 ❌
if (text[k]["code"] !== null)
// 수정한 조건문 ✅
if (text[k]["code"])
=> text[k]["code"] !== null
은 곧, text[k]["code"]
의 값이 Truthy 값일 때를 가리키므로 위와 같이 써주는 것이 더 간결하며 가독성이 좋음
비교연산자를 쓰기 전에 true, false값을 생각해서 조건문을 작성
가독성을 위해 축약해서 작성하는 습관 기르기.
예를 들어,
// 지양하는 코드 ❌
if (person === undefined || person === null)
// 지향하는 코드 ✅
if (!person)
이처럼
true 일 경우) 불필요한 비교연산자 사용없이 true 값만
false일 경우) !
를 이용하면 조건문을 더 간결하게 표현가능, 상황에 따라 !!
또한 사용가능
예제 1)
<div id='my_div'>
안녕하세요? 만나서 반가워요.
<span style='display:none'>숨겨진 텍스트</span>
// 이를 자바스크립트에서 <div id='my_div'> 요소를 잡아 변수로 선언한 뒤
// 각각 경고창으로 호출 할 경우,
예제 2)
어쩌구.innerHTML = "<h1>수박</h1>";
Element
의 속성으로, 해당 Element의 HTML, XML을 읽어오거나, 설정할 수 있다. 예제 1)
예제 2)
수박
Element
의 속성으로, 해당 Element 내에서 사용자에게 '보여지는' 텍스트 값을 읽어온다.
👉 연속되는 공백은 하나의 공백으로만 처리하며, html 태그를 읽고 판별할 수 있음
innerText 프로퍼티를 사용하여도 요소의 '텍스트 콘텐츠' 에만 접근할 수 있다.
< 하지만 아래의 이유로 사용하지 않는 것이 좋다.>
비표준이다.
CSS에 순종적이다. 예를 들어 CSS에 의해 비표시(visibility: hidden;)로 지정되어 있다면 텍스트가 반환되지 않는다.
CSS를 고려해야 하므로 textContent 프로퍼티보다 느리다
예제 1) <span style='display:none'>숨겨진 텍스트</span>
를 읽고 경고창에 띄우지 않음
예제 2) 태그와 같이 <h1>수박</h1>
그대로 텍스트에 출력
textContent
Node
의 속성으로, innetText와는 달리 해상 노드가 가지고 있는 텍스트 값 을 그대로 읽음
👉 태그가 어떤 태그이던지간에 상관없이 모든 태그 안 텍스트만 작성한 그대로 다 읽어옴
성능적인 측면에서 주로 쓰임
예제 1)
예제 2)
innerText와 동일하게 <h1>수박</h1>
그대로 텍스트에 출력
<Node.textContent>
와<HTMLElement.innerText>
차이
textContent
는<script>와 <style>
요소를 포함한 모든 요소의 콘텐츠를 가져오고, 노드의 모든 요소를 반환한다- 반면
innerText는
"사람이 읽을 수 있는" 요소만 처리하고textContent
와 달리 스타일링을 고려하며, "숨겨진" 요소의 텍스트는 반환하지 않는다
<Node.textContent>
와<innerHTML>
과의 차이
Element.innerHTML
는 이름 그대로 HTML을 반환한다 간혹innerHTML
을 사용해 요소의 텍스트를 가져오거나 쓰는 경우가 있지만, HTML로 분석할 필요가 없다는 점에서textContent
의 성능이 더 좋다
🤔 innerHTML을 현업에서 사용하는 경우는 있더라도 극히 드뭅니다.
이유는 말씀해주신 것처럼 보안과 성능 이슈가 맞습니다.
제 개인적인 생각을 말씀드리자면 제품이라는 것은 고객에게 다가갈 때
저희가 만든 어플리케이션, 웹뿐만 아니라 거기서 파생되는 고객이 느끼는 감정,
또는 불편 사항을 최소화 시키는 그런 무형적인 모든 것을 포함시키는 것이라고 생각합니다.
innerHTML을 사용하면 저희가 코드를 적을 때 한군데서 모아볼 수 있다는 편리함이 있지만
그 편리함을 위해서 로딩 속도가 느려지며 보안 이슈가 생길 가능성이 생기므로 유저의 UX 측면에서 문제가 생긴다고 생각합니다.
프로그래머는 프로그램이 잘 동작하는 로직을 생각하는 사람이기도 하지만 자신이 만든 제품이 유저에게 다가갔을 때 어떤 식으로 와닿을지 어떤식으로 작동하면 더 편리하게 좋은 UX를 가지며 사용하게될지 고민해야하는 사람이기도하다고 생각합니다.
결론) innerHTML과 insertAdjacentHTML()은 크로스 스크립팅 공격(XSS: Cross-Site Scripting Attacks)에 취약하다. 따라서 untrusted data의 경우, 주의하여야 한다.
👉 텍스트를 추가 또는 변경시에는 textContent
, 새로운 요소의 추가 또는 삭제시에는 DOM 조작 방식
을 사용하도록 한다.
<div class="numberOfQuiz">
<span class="totalNumber"></span>
<span class="correctNumber"></span>
</div>
// 아래는 수정 후 ✅
<div class="number-quiz">
<span class="total-number"></span>
<span class="correct-number"></span>
</div>
section.quiz.hide {
display: none;
}
//아래와 같이 사용하기 ✅
.hide {
display: none;
}
.show {
display: block;
}
// 21은 내가 아닌 다른 분들이 코드를 볼 경우
// 21이라는 숫자가 무슨 기준인지 무엇을 의미하는지를 단번에 알 수 없기에 지양 ❌
if (text.length === 21) {
nextButton.classList.remove("show");
window.setTimeout(restartGame,2000);
}
// 따로 선언하여 변수명을 통해 그 의미를 보여지는 식으로 코드를 작성하는 것을 지향 ✅
const TOTAL_QUIZ_LENGTH = 21;
if (text.length === TOTAL_QUIZ_LENGTH) {
nextButton.classList.remove("show");
window.setTimeout(restartGame,2000);
}
classList.remove,
classList
를 이용해서 hide와 show 클래스를 만들어 주었을 때 각각 계속 add
로 두 가지 다 만들 필요 없이 처음 한가지 것만 만들어 준 상태로 또 추가하지말고 다시 지우는 기능인 remove
를 이용하여 굳이 두 번 작성 할 필요 없도록.
출처) MDN