
html문서의 계층적 구조와 정보를 표현하며,
이를 제어할 수 있는 프로퍼티와 메서드를 제공하는 트리형 자료구조!

트리 루트노드 ( document )
html문서당 document 객체는 유일하다!
html요소를 가리키는 객체. 문서의 구조를 표현한다
요소 노드의 자식 노드. 해당 노드를 수정하려면 반드시 해당 요소를 거쳐야 한다
요소 노드의 자식 노드.
요소 사이 공백이나 개행도 텍스트 노드가 된다!
😳 노드 객체는 표준 빌트인 객체가 아니다!
브라우저 환경에서 추가적으로 제공하는 호스트 객체.
사용자에게 입력받은 데이터를 innerHTML 프로퍼티에 할당하는 것은 크로스 사이트 스크립팅 공격에 취약하므로 위험하다!
DOMPurify 라이브러리를 사용하여 잠재적 xss위험을 내포한 html마크업 텍스트를 없이 위험을 제거할 수 있다.
HTML요소의 초기 상태 프로퍼티를 지정하며, 변하지 않는다!
어트리뷰트 노드에서 관리된다.
즉, HTML에서 수정되는 요소는 모두 이 DOM 어트리뷰트에 반영되는 것!
언제나 최신 상태를 유지한다.
새로고침을 하면 다시 HTML 어트리뷰트의 값으로 되돌아간다.
😏 setAttribute는 초기상태 값을 변경한다
따라서 HTML어트리뷰트 값을 직접 변경한다!
프로그램의 흐름을 이벤트 중심으로 제어하는 프로그래밍 방식
이벤트가 발생했을 때 호출될 함수.
이때 브라우저에게 이벤트 핸들러 호출을 위임하는 것을 이벤트 핸들러 등록이라고 한다!
이벤트가 발생하면 이벤트에 관련된 정보를 담고 있는 이벤트 객체가 동적으로 생성된다!
브라우저는 이벤트 핸들러를 호출할 때 생성된 이벤트 객체를 첫번째 인수로 전달한다!
| 프로퍼티 | 설명 |
|---|---|
| type | 이벤트 타입 |
| target | 이벤트 발생 dom요소 |
| currentTarget | 이벤트 핸들러가 바인딩된 dom요소 |
| timeStamp | 이벤트 발생 시간 |
dom 트리의 dom 요소 노드에서 발생한 이벤트는 dom트리를 통해 전파된다!
👉 이벤트는 dom트리를 통해 전파되는 이벤트 패스에 위치한 모든 dom 요소에서 캐치가 가능하다!
document.querySelector('p').addEventListener('click', ()=>{..}, true) //버블링 단계에서 캐치
document.querySelector('p').addEventListener('click', ()=>{..}, true) //캡처링 단계에서 캐치
여러 하위 dom요소에 각각의 이벤트 핸들러를 등록하는 대신, 하나의 상위 dom요소에 이벤트 핸들러를 등록하는 방법!
e.preventDefault();
e.stopPropagation();
<button onclick="handleClick(this)">Click me</button>
<script>
function handleClick(button){
console.log(button);//이벤트를 바인딩한 butto
console.log(this); //window
}
</script>
<button class="btn" onclick="handleClick(this)">Click me</button>
<script>
const $button = document.querySelector(".btn");
$button.onclick = function (e){
console.log(e.currentTarget); // $button
console.log(this); // $button
}
//단. 이렇게 화살표 함수로 정의된 경우 화살표함수가 자신의 this를 가지지 않으므로
//상위 스코프의 this를 가져온다.
$button.onclick=(e)=>{
console.log(e.currentTarget); // $button
console.log(this); // window
}
$button.addEventListener("click", functino(e){
console.log(e.currentTarget); // $button
console.log(this); // $button
});
</script>
👉 단, 화살표 함수의 this는 상위 스코프의 this.
js엔진은 싱글 스레드이므로, 타이머 함수들은 비동기 처리 방식으로 동작한다!

짧은 시간 간격으로 이벤트가 연속해서 발생할 때..
👉 이벤트 핸들러를 호출하지 않다가, 일정 시간동안 이벤트가 더 이상 발생하지 않으면 그때 한 번만 이벤트 핸들러를 호출!
const debounce = (callback, delay) =>{
let timeId;
return event => {
if(timeId) clearTimeout(timerId)
timerId = setTimeout(callback, delay, event);
//새 이벤트가 발생하면, 다시 처음부터 초를 센다..
};
};

짧은 시간 간격으로 연속해서 이벤트가 발생할 때..
👉 이벤트를 그룹화하여 일정 시간 단위로 이벤트 핸들러가 호출되도록 호출 주기를 만든다!
👉 따라서 delay 시간 간격으로 콜백 함수가 호출된다!
const throttle = (callback, delay) =>{
let timeId;
return event => {
if(timeId) return;
timerId = setTimeout(()=>{
callback(event);
timeId = null;
}, delay, event);
};
};
js엔진은 단 하나의 실행 컨텍스트 스택을 갖는다.
js엔진은 한번에 하나의 태스크만 실행하는 싱글스레드 방식이므로, 처리에 시간이 걸리는 태스크를 실행하는 경우 다른 한 작업이 중단된다.
👉 이렇게 한 번에 하나씩만 수행할 수 있는 것을 비동기라고 한다!
😌 js의 내장 비동기 함수들
타이머 함수, http 요청, 이벤트 핸들러
js의 동시성을 지원하는 브라우저 기능!

js의 실행 컨텍스트 스택
객체가 저장되는 메모리 공간.
객체 크기에 따라 메모리 크기를 런타임에 동적할당하므로 구조화되어있지 않다!
비동기 함수의 콜백함수나 이벤트 핸들러가 일시적으로 보관되는 영역
콜 스택에 실행 중인 컨텍스트가 있는가?
태스크 큐에 대기중인 함수가 있는가?
를 확인하여 태스크 큐에서 콜 스택으로 함수를 옮겨 실행하는 루프!
👉 비동기 함수의 콜백 함수는 태스크 큐에 푸시되어 대기하다가, 다른 함수가 모두 종료되면 비로소 콜 스택에 푸시되어 실행된다!

AJAX 내 반쪽 아니 완 전 카피~
브라우저가 서버에게 비동기 방식으로 데이터를 요청하고,
서버가 데이터를 수신하여 웹페이지를 동적 갱신하는 프로그래밍 방식
브라우저 제공하는 web api.
http 비동기 통신을 제공한다.
👉 ajax는 이러한 전통적인 패러다임에서 벗어나, 변하지 않은 부분은 다시 렌더링하지 않는다!
http를 기반으로 클라이언트가 서버의 리소스에 접근하는 방식을 규정한 아키텍처
특정 리소스를 식별하는 데 사용되는 고유한 문자열 시퀀스를 말한다!
😆 URI 구조
scheme://user:password@host:port/path?query#fragment
scheme : 사용할 프로토콜을 뜻하며 웹에서는 http 또는 https를 사용
host와 port : 서버 호스트명과 포트번호
path : 서버 경로에 대한 상세 정보
query : 접근할 대상에 전달하는 파라미터
fragment : 서브 리소스 식별 정보
클라이언트가 웹 서버에게 사용자 요청의 목적과 종류를 알려줄 때 사용한다.
GET, POST, DELETE...
전송되는 데이터!
동사보다는 명사를 사용하여 리소스를 표현한다!
# bad
GET /getTodos/1
# good
GET /todos/1
| HTTP 요청 메서드 | 종류 | 목적 | 페이로드 |
|---|---|---|---|
| GET | index/retrieve | 모든/특정 리소스 취득 | X |
| POST | create | 리소스 생성 | O |
| PUT | replace | 소스 교체 | O |
| PATCH | modify | 리소스 일부 수정 | O |
| DELETE | delete | 리로스 삭제 | X |
비동기 함수는 비동기 처리 결과를 외부에 반환할 수도, 상위스코프 변수에 할당할 수도 없다!
👉 따라서 비동기 함수의 처리 결과와 후속 처리는 비동기 함수 내에세서 수행해야 한다.
👉 이것이 반복되면, 비동기 내 비동기 내 비동기 내 비동기함수 사용이 되는데..
👉 이것을 콜백 헬이라고 한다.
에러가 호출자 방향으로 전파된다!
이렇게 전파된 에러는 catch에서 캐치되지 않는다!
프로미스란, 비동기 처리 상태와 처리 결과를 관리하는 객체를 말한다!

😏 settled 상태란?
fulfilled, rejected 상태와 상관 없이 비동기 처리가 수행된 상태를 말한다!
한번 settled ㄷ상태가 되면 다른 상태로 변화할 수 없다!
//성공
new Provise(resolve=>resolve("fulfilled"))
.then(v=>conosle.log(v), e=>console.error(e));
//실패
new Provise((_,resolve)=>resolve("fulfilled"))
.then(v=>conosle.log(v), e=>console.error(e));
👉 then 메서드는 언제나 프로미스를 반환한다!
👉 프로미스가 아닌 값을 반환하면 그 값을 암묵적으로 resolve, reject하여 프로미스를 생성해 반환한다!
🤭 프로미스 후속 처리 메서드
프로미스의 비동기 처리 상태가 변화하면, 후속 처리 메서드에 인수로 전달한 콜백 함수가 호출된다!
then, catch(에러), finally(에러, 성공 상관없이 공통 처리)..
프로미스 후속 처리 메서드는 언제나 프로미스를 반환하므로, 연속적으로 사용할 수 있다.
promiseGet(`url`).then(({userId})=> promiseGet(`url/${userId}`)))
.then(...)
.catch(...)
전달받은 값을 resolve or reject하는 프로미스를 생성한다.
const resolvePromise = Promise.resolve([1,2,3]);
resolvePromise.then(console.log); //[1,2,3]
const rejectPromise = Promise.reject(new Error('error'));
rejectPromise.catch(console.log); //error
여러 개의 비동기처리를 병렬 처리할 때 사용한다.
처리 순서를 보장하며, 하나라도 reject되면 즉시 종료한다.
const promise1=new Promise(resolve=>setTimeout(()=>resolve(1),3000));
const promise2=new Promise(resolve=>setTimeout(()=>resolve(2),2000));
const promise3=new Promise(resolve=>setTimeout(()=>resolve(3),1000));
//Promise.all을 쓰지 않으면 6초 소요
const res=[];
promise1().then(data=>{res.push(data); return promise2();})
.then(data=>{res.push(data); return promise3();})
.then(data=>{res.push(data); console.log(res);})
.catch(console.log(error));
//Promise.all을 쓰면 3초 소요
Promise.all([promise1(), promise2(), promise3()])
.then(console.log) //1,2,3
.catch(console.log(error));
가장 먼저 fulfilled된 상태의 프로미스 처리결과를 resolve하는 프로미스를 반환한다.
Promise.race([promise1(), promise2(), promise3()]).
.then(console.log) //3
.catch(console.log);
프로미스가 모두 settled상태가 되면 처리 결과를 배열로 반환한다.
즉, reject도 반환하는 Promise.all이라고 생각하면 될 듯!
setTimeout(()=>console.log(1),0);
Promise.resolve().then(()=>console.log(2)).then(()=>console.log(3));
//우리의 예상: 1, 2, 3
//실제로는..: 2, 3, 1
태스크 큐의 우선순위 < 마이크로 태스크 큐
마이크로 태스크 큐의 모든 프로미스 후속처리메서드 콜백 함수를 실행하고 나서야
이벤트 루프에서 태스크 큐의 함수가 실행된다!
http 요청 전송 기능을 제공하는 클라이언트 사이드 web api
[ [ http응답을 나타내는 Response 객체 ] 를 래핑한 Promise 객체 ]를 반환한다!
단, http 에러(404, 500..)는 reject하지 않는다!
👉 대신 Response객체의 ok속성 상태를 false로 해서 return한다!
👉 네트워크 장애, CORS 에러에 의한 경우만 프로미스를 rejec한다!
😏 그런 면에서 axios는...
모든 http 에러를 reject해준다!!
const request = {
get(url){ return fetch(url);},
post(url, payload){
return fetch(url, {
method:"POST",
headers: {"content-Type":"application/json"},
body: JSON.stringify(payload)
});},
patch(url, payload){
return fetch(url, {
method: "PATCH",
headers: {"content-Type":"application/json"},
body: JSON.stringify(payload)
});},
delete(url){ return fetch(url, {method: "DELETE"});
}
}
코드 블록 실행을 일시중지했다가 필요시점에 다시 재개할 수 있는 특수한 함수!
이러한 제네레이터의 가독성을 좋게 한 것이 async/await이다!
화살표 함수나 생성자 함수로 호출할 수 없다!
function* getDecFunc(){ yield 1; }
에러가 발생해도 프로그램이 강제종료되지 않는다!
try{
//실행 코드
throw new Error("에러발생!"); //catch로 Error 객체 던짐
}.catch(err){
//실행 코드에서 에러 발생시 catch로 Error객체 전달
}.finally{
//에러 발생과 상관없이 반드시 한 번 실행
}
에러 메시지를 인수로 전달하는 것이 가능하다!

👉 throw된 에러를 캐치되지 않으면 호출자 방향으로 전파된다!
👉 error를 아무도 캐치하지 않으면 프로그램은 강제 종료된다!
🥺 비동기 함수 setTimeout나 프로미스 후속처리메서드는 호출자가 없어요
이러한 함수들의 실행 컨텍스트는 콜스택의 가장 하부에 존재하게 되기 떄문에, 에러를 전파할 호출자가 존재하지 않는다!
애플리케이션을 구성하는 개별적 요소로써 재사용 가능한 코드 조각을 의미한다!
모듈은 공개가 필요한 자산에 한정하여 명시적으로 선택적 공개가 가능하다. 이것이 export!
모듈 사용자는 모듈이 공개한 자산을 자신의 스코프로 가져와 사용할 수 있다. 이것이 import!
😧 초반에는 말입니다
js에는 모듈이 존재하지 않았다!
대신 script 태그로 모든 파일이 하나의 js에 있는 것처럼 동작시킬 수는 있었다.
이는 하나의 전역을 공유하여 변수 중복 등의 문제를 야기했다.
import * as lib from "./lib.js";
console.log(lib.pi);