HTML 요소들을 객체화 하여 조작하기 편리하게 만든 모델
const tweetDiv = document.createElement('div')
document.body.append(tweetDiv)
const tweets = document.querySelectorAll('.tweet') // returns Array-like Object
document 하위 DOM 객체에 대해서도 querySelector 적용 가능하다.
유연한 querySelector 예시
const el = document.querySelector("div.user-panel:not(.main) input[name='login']");
배열처럼 동작하지만 배열의 인터페이스를 모두 제공하진 않는다.
const arrLikeObj = document.querySelector('body').children // returns <HTMLCollection> obj
arrLikeObj.forEach(e => console.dir(e)); // Error
Array.from(arrLikeObj).forEach(e => console.dir(e)); // Works
const nodeList = document.querySelectorAll('.tweet'); // returns <nodeList> object
nodeList.forEach(e => console.dir(e)); // Works on <nodeList> object
nodeList.reduce(e => e + 1); // reduce does not works on nodeList -array like object
//using spread operator to convert nodelist to array
const nodeListArr = [...nodeList] // now reduce, map works on nodeListArr
성능이나 가독성을 위해 임시로 사용하는 HTML 엘리먼트 조각
메인 DOM에 들어가지 않으므로 page reflow를 발생시키지 않는다.
John Resig님에 따르면 요정도로 빠르다 카더라
const $fragment = document.createDocumentFragment();
[1, 2, 3, 4].forEach(() => {
const rowData = [];
// data.push(rowData);
const $tr = document.createElement('tr');
[1, 2, 3, 4,].forEach(() => {
// rowData.push(0);
const $td = document.createElement('td');
$tr.appendChild($td);
});
$fragment.appendChild($tr);
});
console.log($fragment);
$table.appendChild($fragment);
말 그대로 템플릿을 담은 태그다.
html에 포함되어 있지만 페이지 로딩시에 바로 화면에 보여주지 않고, 자바스크립트를 통해
데이터를 입력하면 화면에 나타나게 하는 것.
최근에는 템플릿 엔진이 있으므로 굳이 활용하지는 않을 것 같다.
노드는 웹 문서안의 모든 요소를 의미한다. 주석도 노드가 된다.
element는 html태그로 둘러쌓인 노드를 의미한다. 엘리먼트는 특별한 노드이므로 id나 class를 가질 수 있다.
document.querySelector("#main").childNodes // 모든 자식 노드를 반환(주석도)
document.querySelector("#main").children // 모든 자식 element(=element node)를 반환
생성한 tweetDiv 를 container 에 넣기 위해서는, container 를 먼저 찾아야 합니다. 어떻게 container 를 찾을 수 있을까요? 위에서 언급했던 DOM 트리를 순회해서 찾을 수 있습니다. 그러나 보다 더 편리한 방법이 있으니 검색해보시기 바랍니다.
<div class="a">
<span></span>
</div>
<div class="b"></div>
const divB = document.querySelector(‘.b’);
divB.appendChild(span);
span은 어디로 갈까?
1. a에 그대로 있나?
2. 양쪽에 다 포함되나?
3. b로 이동하나?
답은 3번 b로 이동한다.
객체이므로 포인터만 바꿔주니까 이동할 것이라고 직관적으로 이해했다.
아래에 더 상세한 설명있음.
관련 글
정규식 정리, 다음 강의를 수강하면서 정리해본다. 정규표현식 , 더이상 미루지 말자 🤩
드림코딩 채널인데, 정규식이라는 내용자체는 어떤 자료를 가지고해도 대동소이하겠지만 강사 엘리님의 목소리와 발음이 좋고, 진행을 지루하지 않게 잘 해주셔서 자주 찾게 되는 것 같다.
결국 서비스의 성패는 비기능적 요구사항에 달려 있다는 생각이 든다. 기능적 요구사항을 충족하는 것은 당연히 기본중의 기본이고...
1. Group
|
또는
()
그룹
[]
문자셋, 괄호안의 어떤 문자든지 매칭
[^]
부정 문자셋, 괄호안의 모든 문자도 아닌 것
(?:)
찾지만 기억하진 않음
2. Quantifier
?
: zero or one
*
: zero or more
+
: one or more
{n}
: n번 반복
{min,}
{min,max}
3. Boundary
\b
: 단어 경계, 단어의 앞이나 뒤에 붙여 시작과 끝을 명시 가능
\B
: 단어 경계가 아님, 소문자\b
의 반대 역할
^
: 줄 단위 시작 경계, 멀티라인모드 아닐시 전체 문서대상
$
: 줄 단위 끝 경계, 멀티라인 아닐시 전체 문서를 대상
4. Character Classes
\
: 이스케이프
.
: 줄바뀜 문자가아닌 모든 문자
\d
: 숫자
\D
: 숫자 아님
\w
: 문자
\W
: 문자 아님
\s
: 공백
\S
: 공백 아님
Quiz
아래의 정규식을 해석해 보세요.
그룹핑을 잘 활용하면 엄청 편리합니다.
그리고 특정 그룹의 데이터를 가져오지 않으려면 어떻게 할까요?
Regex in JS
url.match()가 배열을 반환한다는 점을 유의!
유효성 검사의 최초 과제는 쉽게 해결했으나, 추가 기능 구현에서 예상치 못한 버그가 발생했고, 페어분과 해결하면서 많은 공부가 되었다. 페어분에게 다시 한번 감사드린다.
오류는 forEach 루프에서 return를 하고 break처럼 작동한다고 착각해서 발생하였다.
foreEach에서는 break가 동작하지 않고, forEach를 every로 바꾸고 return false;
하면 break 처럼 동작한다. 아래 코드가 제대로 동작하는 샘플
enroll.addEventListener('change', () => {
if (elPassword.value !== elPasswordRetype.value) {
submitBtn.disabled = true;
return;
}
enroll.querySelectorAll('input').forEach(elem => {
if (elem.value.length === 0) {
submitBtn.disabled = true;
return // ERROR HERE!!!
}
submitBtn.disabled = false;
});
});
// Fixed Like Below
enroll.addEventListener('change', () => {
if (elPassword.value !== elPasswordRetype.value) {
submitBtn.disabled = true;
return;
}
enroll.querySelectorAll('input').every(elem => {
if (elem.value.length === 0) {
submitBtn.disabled = true;
return false;
}
submitBtn.disabled = false;
});
});