JavaScript with VsCode

DOM 제어를 위한 학습(Function, Event, Ajax)
SHIN's avatar
Aug 29, 2024
JavaScript with VsCode
 

ShortCut

💡
줄 이동 : Opt + Shft + 화살표 줄 복사 : Cmd + D
Node.js(without Browser ) = Javascript
 

let vs var

💡
- 변수의 scope 차이
 
 

1. Hosting

💡
- 코드 실행 전 변수선언/함수선언 을 해당 스코프의 최상단으로 끌어올리는 것이 아님 - 끌어 올려진 것 같은 현상을 말함 * js 엔진은 코드 실행 전 코드를 형상화하고 구분하는 과정(실행 context를 위한 과정)을 거침. → 즉 실행 전 실행 context를 위한 과정에서 모든 선언(var, let, const, function, class)을 스코프에 등록함 - 코드 실행 전 이미 변수선언/함수선언 이 저장되어 있기에 선언문보다 참조/호출이 먼저 나와도 오류 없이 동작함 (정확히는 var 키워드로 선언한 변수와 함수 선언문일 경우 오류 없이 동작. 이는 선언이 파일의 맨 위로 끌어올려진 것처럼 보이게 함) - *실행 context는 실행 가능한 코드가 실행되기 위해 필요한 환경을 의미. 실행되기 전 이러한 실행 context 과정(코드를 구분하는 과정)을 거침
 

1-1. 변수 Hoisting (var, let, const 키워드)

  • var 키워드로 선언된 변수와는 달리 let 키워드로 선언된 변수를 선언문 이전에 참조하면 참조 에러 (Reference Error)가 발생 → 이는 let 키워드로 선언된 변수는 스코프의 시작에서 변수의 선언까지 *일시적 사각지대(Temporal Dead Zone; TDZ)에 빠지기 때문.
💡
!! 이 Hoisting이란 용어가 ‘선언이 먼저 메모리에 저장되었다’ 를 의미하기에, 즉 ‘선언이 끌어올려진다’는 의미라서 모든 선언은 Hoisting이 일어난다는 말은 참. → 선언문 이전에 참조해서 에러를 발생시킨다고 Hoisting이 일어나지 않은 것은 아니라는 것.
 

1-2. Ex 코드

let foo = 1; { console.log(foo); let foo = 2; }
 

1-3. 변수 생성 방법 및 Hoisting

  1. 선언 단계(Declaration phase)
      • 변수를 실행 context의 변수 객체에 등록
      • 이 변수 객체는 스코프가 참조하는 대상이 됨
 
  1. 초기화 단계(Initialization phase)
      • 변수 객체에 등록된 변수를 위한 공간을 메모리에 확보
      • 이 단계에서 변수는 undefined로 초기화 됨
 
  1. 할당 단계(Assignment phase)
      • undefined로 초기화 된 변수에 실제 값을 할당
 

 

2. 함수 & 람다식 표현 정리

2-1. 익명 함수 (Noname Function)

let f = function () { console.log("fun2 함수"); }; f(); // "fun2 함수" 출력 // 변수에 담을 수 있는 근거 = JS는 1급객체라. => 매개 변수에 전달 가능
  • function () { … } = 익명 함수.
  • 이 함수는 변수 f 에 할당되어 f() 호출 시 함수 실행
 

2-2. 함수 표현식 (Function Expression)

💡
함수 정의 및 그 값을 변수에 할당하는 방식. Return 값이 있는 경우 이를 표현
let f1 = function () { console.log("fun3 함수"); return 1; // return이 있으므로 표현식으로 간주됨 }; let result = f1(); // "fun3 함수" 출력, result는 1
 
 

2-3. 람다 표현식 (Arrow Function)

💡
익명 함수 사용 시 간결하게 작성하기 위한 방식
let f2 = () => { return 1; }; let result2 = f2(); // result2는 1
 
축약 함수
let f3 = () => 3; let result3 = f3(); // result3는 3 let f4 = () => { console.log(1); }; // 코드 처리가 많을 땐 이거로 처리
  • { } 없이 return 생략, 바로 작성 시 해당 값 자동 return
 
let f = function () { // 익명 함수 (noname funtion) console.log("fun2 함수"); } f(); // 변수에 담을 수 있는 근거 = JS는 1급객체라. => 매개 변수에 전달 가능 let f1 = function () { // 표현식(expression) = return 되야함=람다식, 하지만 이 라인은 아님. -> 내부에서 실행만 됨 console.log("fun3 함수"); return 1; // expression으로 바뀌려면 이렇게 } f1(); let f2 = () => { return 1; // 람다표현식 / 람다식은 console로 처리. } f2(); let f3 = () => 3; // {} 없으면 $표현식 -> 자동 return 됨 => 람다 표현식 / 간단한 연산 처리 시 사용 let f4 = () => { console.log(1); }; // 람다식 / 코드 처리가 많을 땐 이거로 // 매개변수에 함수를 전달하기 위해 () => 1; 이거로 전달 가능 = 가독성 UP
 

3. Event with Ajax - DOM 제어

 
  • addEventListener() 메소드를 통해 Event Handler 등록
<button id="myBtn">Click me</button> <script> const myBtn = document.getElementById("myBtn"); myBtn.addEventListener("click", function() { alert("Hello World!"); }); </script>
→ HTML과 JS 코드를 분리해서 유지 보수 쉽게 가능.
addEventListener() 메소드는 Event 이름과 Event Handler 함수를 인자로 받음
 
 

3-1. Test(실습)

💡
1. click : 요소 클릭시 발생 2. dbclick : 요소 더블 클릭 시 발생 3. mousedown : 요소에서 마우스 버튼이 눌릴 때 발생 4. mouseup : 요소에서 마우스 버튼이 떼어질 때 발생 5. mousemove : 요소에서 마우스가 움직일 때 발생 6. mouseover : 요소에 마우스 커서가 올라갈 때 발생 7. mouseout : 요소에서 마우스 커서가 벗어날 때 발생 8. keydown & keyup : 키보드에서 키를 누르거나 뗄 때 발생 9. submit : 폼 제출 시 발생 10. change : 요소의 값 변경 시 발생 11. load : 웹 페이지나 이미지 등이 로딩 시 발생
 
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <button id="myBtn">Click me</button> <input type="text" id="myIp"> <script> // ex) 더블 클릭으로 e 발생 const myBtn = document.getElementById("myBtn"); myBtn.addEventListener("click", function (e) { console.log(e); }); const myIp = document.getElementById("myIp"); myIp.addEventListener("change", function (e) { console.log(e); console.log(e.target.value); }); </script> </body> </html>
notion image
 
 

3-2. DOM 숨기기

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .box { border: 1px solid black; padding: 10px; } </style> </head> <body> <h1>숨기기</h1> <button onclick="hideDisplay()">display로 숨기기</button> <button onclick="hideVisible()">visible로 숨기기</button> <div class="box"> <div class="box" id="innerBox1"> 내부박스1</div> <div class="box" id="innerBox2"> 내부박스2 </div> </div> <script> function hideDisplay() { let el = document.querySelector("#innerBox1"); el.style.display = "none"; // } function hideVisible() { let el = document.querySelector("#innerBox2"); el.style.visibility = "hidden"; // 영역이 남은채로 해당 부분이 사라짐 } </script> </body> </html>
 
display = “none”;
notion image
visibility = “hidden”
notion image
 
 

3-3. DOM 나타내기

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .box { border: 1px solid black; padding: 10px; } #innerBox1 { display: none; } #innerBox2 { visibility: hidden; } </style> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> </head> <body> <h1>나타내기</h1> <button onclick="showByDisplay()">display로 나타내기</button> <button onclick="showByVisible()">visible로 나타내기</button> <div class="box" id="outerBox"> <div class="box" id="innerBox1"> 내부박스1 </div> <div class="box" id="innerBox2"> 내부박스2 </div> </div> <script> function showByDisplay() { // let el = document.querySelector("#innerBox1"); // el.style.display = "block"; // 전체 영역 차지 $("#innerBox1").css("display", "block"); } function showByVisible() { // let el = document.querySelector("#innerBox2"); // el.style.visibility = "visible"; $("#innerBox2").css("visability", "visible"); } </script> </body> </html>
 
notion image
→ 버튼 클릭 시 나타남
 

3-4. DOM 추가하기 (Ajax로 코드 간결화)

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .box { border: 1px solid black; padding: 10px; } </style> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> </head> <body> <h1>추가하기</h1> <button onclick="addAppend()">append로 추가하기</button> <button onclick="addPrepend()">prepend로 추가하기</button> <button onclick="addBefore()">before로 추가하기</button> <button onclick="addAfter()">after로 추가하기</button> <div class="box" id="outerBox"> </div> <script> function render(id, text) { return `<div class="box" id="${id}"> ${text}</div>`; } function addAppend() { let box = render("inner1", "내부박스1"); $("#outerBox").append(box) /* let newEl = document.createElement("div"); // 빈 dom 생성 newEl.setAttribute("class", "box"); newEl.setAttribute("id", "innerBox1"); newEl.innerHTML = "내부박스1"; let el = document.querySelector("#outerBox"); el.append(newEl); */ } function addPrepend() { let box = render("inner2", "내부박스2"); $("#outerBox").prepend(box); /* let newEl = document.createElement("div"); newEl.setAttribute("class", "box"); newEl.setAttribute("id", "innerBox2"); newEl.innerHTML = "내부박스2"; let el = document.querySelector("#outerBox"); el.prepend(newEl); */ } function addBefore() { let box = render("outer1", "외부박스1"); $("#outerBox").before(box); } function addAfter() { let box = render("outer2", "외부박스2"); $("#outerBox").after(box); } /* function addBefore() { let newEl = document.createElement("div"); newEl.setAttribute("class", "box"); newEl.setAttribute("id", "innerBox3"); newEl.innerHTML = "내부박스3"; let el = document.querySelector("#outerBox"); el.before(newEl); } function addAfter() { let newEl = document.createElement("div"); newEl.setAttribute("class", "box"); newEl.setAttribute("id", "innerBox4"); newEl.innerHTML = "내부박스4"; let el = document.querySelector("#outerBox"); el.after(newEl); } */ </script> </body> </html>
  • append : 차례대로 쌓임 - 내부박스1
  • prepend : 최신순으로 쌓임 (댓글 등록 구현 시 사용) - 내부박스 2
  • before : 내부 박스 외부에 최신순으로 쌓임 - 외부 박스1
  • after : 내부 박스 외부에 차례대로 쌓임 (오래된 순) - 외부 박스2
notion image
 

3-5. DOM 삭제하기

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .box { border: 1px solid black; padding: 10px; } </style> </head> <body> <h1>삭제하기</h1> <button onclick="del()">remove로 삭제하기</button> <div class="box" id="outerBox"> <div class="box" id="innerBox1"> 내부박스1 </div> </div> <script> function del() { let el = document.querySelector("#innerBox1"); el.remove(); } </script> </body> </html>
 
  • 삭제 전
notion image
 
  • 삭제 후 (클릭 후)
    • notion image
 
 

3-6. DOM List 추가하기 - 반복문으로 리스트 만들기

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .box { display: grid; grid-template-columns: 1fr 1fr 1fr; border: 1px solid black; padding: 10px; } .card { border: 1px solid lightgray; box-shadow: 0 4px 4px 0 grey; padding: 10px; margin: 5px; border-radius: 5px; } </style> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> </head> <body> <h1>반복문으로 리스트 만들기</h1> <button onclick="render()">render</button> <div class="box" id="outerBox"> </div> <script> // 1. 그림 그리기 function render() { for (let i = 1; i < 5; i++) { $("#outerBox").append(makeCard(i)); } } // 2. DOM 만들기 function makeCard(id) { return `<div id="card-${id}" class="card"> <h3>제목${id} 입니다</h3> <p>내용${id} 입니다</p> <button onclick="del(${id})">삭제</button> </div>`; } function del(id) { $(`#card-${id}`).remove(); } </script> </body> </html>
 
  • Render 버튼 클릭으로 box 생성 (for문으로 5개 미만으로 생성 - 총 4개)
notion image
 
  • 이후 해당 card-{id} 삭제 시 해당 번호 삭제
notion image
 
 

3-7. Fetch with Ajax

  • 설명은 주석에 추가해서 한 번에 정리
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> </head> <body> <div id="root"> </div> <script> function makeDom() { return `<div>그림</div>`; } function download() { const xhr = new XMLHttpRequest(); xhr.open("GET", "http://localhost:8080/test", false); // false는 동기 요청을 의미함 xhr.send(); return xhr; } $("#root").append(makeDom()); $("#root").append(makeDom()); let xhr = download(); $("#root").append(`<div>${xhr.responseText}</div>`); $("#root").append(makeDom()); </script> </body> </html> 4:06 <!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> </head> <body> <div id="root"> </div> <script> function makeDom() { return `<div>그림</div>`; } async function download() { // 비동기로 실행 되야 함 -> 1. 무거운 코드를 함수로 만들어서 분리 / 2. 비동기 함수로 수정 / let response = await fetch("http://192.168.0.99:8080/test"); // 이런 통신 방법은 io가 일어남 = 오래 걸림 -> 즉 이런 작업들은 실행 시 Promise(어음=pending)를 줌 // promise 객체 -> response 부분에 promise가 아닌 결정체를 받고싶음 // 즉 promise를 안 받기 위해서 await 사용 -> 5초 걸린 후 리얼 값을 넘김. 5초 후 json으로 파싱. // 여기서 async (비동기함수)를 걸면 5초 걸리는 부분을 체크포인트로 잡고 함수를 빠져나옴 // 빠져나오면 메모리는 일(다운)을 계속 하고 있고 cpu는 그 밑의 라인들 실행 ~ 이후 할 일 없으면 await로 다시 back // let data = await response.json(); // 파싱 -> 5초 후 들어와서 5초 후 실행 $("#root").append(`<div>${data.body}</div`); } $("#root").append(makeDom()); $("#root").append(makeDom()); download(); $("#root").append(makeDom()); </script> </body> </html>
 
Share article

SHIN