[TIL] 22.10.21

nana·2022년 10월 21일
0

TIL

목록 보기
13/50
post-thumbnail

오늘 배운 것 - Javascript


1. 파싱 과정

2. 반복분

  • for 문
  • while 문
  • for in 문 (객체)
  • for of 문 (배열)

3. setTimeout()

4. setInterval()

5. clearInterval()

6. 매개변수, 전달인자

7. Web Storage

  • Session Storage
  • Local Storage

실습) D-day 카운터 만들기




파싱 과정

브라우저에서 태그를 해석하는 과정을 파싱 과정이라고 한다.

Html파일 내에서 스크립트 태그 위치에 따라 에러가 발생하는 경우가 있다.

파싱 과정에서 script태그를 만나면 html 파싱 과정이 중단되고, script파일을 먼저 읽은 후에 html을 읽기 때문에 script에 작성된 id값들이 정의되지 않는 오류가 발생한다.

script태그에 defer를 추가해주면 html과 script파일이 동시에 파싱 진행되어 오류가 발생하지 않는다.

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

반복문

1) for 문

for (let i = 0; i < 10; i++) {
	console.log(i)
}

2) while 문

최초식을 바깥에 작성한다.

let i = 0;		// 최초식

while (i < 10) {
	console.log(i)
  	i = i + 1	// 증감문이 while 안에 위치한다.
}

📌 while문은 종료 조건을 설정하지 않으면 무한 반복이 되므로 유의한다.

let i = 0;
let status = true

while (status === true) {
	console.log(i)
  	
  	if (i >10) {		// 종료 조건
    	status = false
    }
      
  	i = i + 1	
}

3) for in 문

객체에 사용한다.
객체의 key값들을 불러와 준다.

for (let key in 객체) {
	console.log(key);
}

4) for of 문

배열에 사용한다.
주어진 배열의 요소를 변수 명으로 가져온다.

for (let tag of 배열) {
	console.log(tag)
}

setTimeout()

함수의 실행을 지정한 시간동안 지연시켜 준다.

  for (let i = 0; i < 100; i++) {
     setTimeout(counterMaker, 1000 * i);// counterMaker함수가 1*i 초 후 실행된다.
  }

setInterval()

지정한 시간마다 함수를 실행시킨다.

setInterval(test, 1000)	// 소괄호 없이 함수 이름만 넣어준다.

setInterval은 실행될 때 마다 인터벌마다 고유한 id값을 가진다.
id값과 clearInterval 이용하여 반복을 중지시켜 줄 수 있다.


clearInterval()

배열에 setInterval로 실행된 id값을 넣어준 후,
clearInterval(id)로 모든 인터벌을 종료 시킬 수 있다.


함수의 매개변수, 전달 인자

전달 인자로 함수의 외부에서 데이터를 전달 받고, 전달된 데이터는 함수 내부에서 매개 변수로서 활용할 수 있다.

1) 매개변수 (Parameter)

함수를 선언할 때, 소괄호 안에 정의되는 변수이다.


2) 전달인자 (Arguments)

함수를 호출할 때, 함수 내부로 전달되는 데이터이다.

const sum = function (a, b) {	// a,b : 매개변수
	let result = a + b;
  	return result
}

sum()	// undefined
sum(10, 20) 	// 10, 20 : 전달인자. 결과값은 30 

Web Storage

브라우저에 내에 존재하는 데이터 저장소이다.
Session Storage와 Local Storage가 있다.

공통점

  • 로컬 환경에 데이터를 저장한다.
  • 데이터가 key / value 형태로 저장된다.

1) Session Storage

  • 세선 단위로 구분되며 활용된다.

  • 브라우저, 탭을 종료하면 데이터가 영구적으로 삭제된다.

📌 세션 : 사용자의 웹 페이지 접속 상태에 따른 단위


2) Local Storage

  • 도메인 단위로 구분되며 활용된다.

  • 브라우저 자체를 종료해도 데이터가 존재한다.

  • 크롬 개발자 도구 Application > Storage > Local Storage에서 key와 value를 확인할 수 있다.


실습) D-day 카운터 만들기

const messageContainer = document.querySelector("#d-day-message");
const container = document.querySelector("#d-day-container");
const savedDate = localStorage.getItem("saved-date"); // 가져오고 싶은 데이터의 key를 입력해준다.

const intervalIdArr = [];

container.style.display = "none";
messageContainer.innerHTML = "<h3>D-Day를 입력해 주세요.</h3>"; // innerHTML: 내부 html태그 추가

const dateFormMaker = function () {
  const inputYear = document.querySelector("#target-year-input").value;
  const inputMonth = document.querySelector("#target-month-input").value;
  const inputDate = document.querySelector("#target-date-input").value;

  // const dateFormat = inputYear + '-' + inputMonth + '-' + inputDate;  // 지역변수(함수 안에서 선언됨)
  const dateFormat = `${inputYear}-${inputMonth}-${inputDate}`;

  return dateFormat;
};

const counterMaker = function (data) {
  if (data !== savedDate) {
    //input 데이터와 savedDate가 다를때 (새로운 데이터가 들어올 때)
    localStorage.setItem("saved-date", data); // local storage로 저장한다.
  }
  const nowDate = new Date(); // 현재 시간
  const targetDate = new Date(data).setHours(0, 0, 0, 0); // 구하려는 D-day 날짜. setHours는 시간대 변경
  const remaining = (targetDate - nowDate) / 1000; // D-day 까지의 남은 시간(초)

  if (remaining <= 0) {
    // 만약, remaining이 0이거나 음수라면, 타이머가 종료되었습니다. 출력
    container.style.display = "none";
    messageContainer.innerHTML = "<h3>타이머가 종료되었습니다.</h3>";
    messageContainer.style.display = "flex";
    setClearInterval(); // 불필요한 반복을 종료시킨다.
    return; // 조건이 맞다면 return으로 불필요한 연산을 줄이기 위해 함수를 종료시켜준다.
  } else if (isNaN(remaining)) {
    // 만약, 잘못된 날짜가 입력되었다면, 유효한 시간대가 아닙니다. 출력
    container.style.display = "none";
    messageContainer.innerHTML = "<h3>유효한 시간대가 아닙니다.</h3>";
    messageContainer.style.display = "flex";
    setClearInterval();
    return;
  }

  //   const remainingDate = Math.floor(remaining / 3600 / 24); // 3600(시간) 으로 나눈 후, 24로 나누면 며칠이 남았는지 알려준다.
  //   const remainingHours = Math.floor(remaining / 3600) % 24; // 남은 시간을 알려준다.
  //   const remainingMin = Math.floor(remaining / 60) % 60; // 남은 분을 알려준다.
  //   const remainingSec = Math.floor(remaining) % 60; // 남은 초를 알려준다.

  // 객체로 변경
  const remainingObj = {
    remainingDate: Math.floor(remaining / 3600 / 24),
    remainingHours: Math.floor(remaining / 3600) % 24,
    remainingMin: Math.floor(remaining / 60) % 60,
    remainingSec: Math.floor(remaining) % 60,
  };

  //   documentObj["days"].textContent = remainingObj["remainingDate"];
  //   documentObj["hours"].textContent = remainingObj["remainingHours"];
  //   documentObj["min"].textContent = remainingObj["remainingMin"];
  //   documentObj["sec"].textContent = remainingObj["remainingSec"];

  // 반복문으로 변경
  const documentArr = ["days", "hours", "min", "sec"];
  const timeKeys = Object.keys(remainingObj);

  const format = function (time) {
    // 남은 시간이 한자리수라면 0을 붙인다.
    if (time < 10) {
      return "0" + time;
    } else {
      return time;
    }
  };

  let i = 0;
  for (let tag of documentArr) {
    const remainingTime = format(remainingObj[timeKeys[i]]);
    document.getElementById(tag).textContent = remainingTime;
    i++;
  }
};

// 타이머 시작
const starter = function (targetDateInput) {
  if (!targetDateInput) {
    // targetDateInput이 undefined라면
    targetDateInput = dateFormMaker();
  }

  // const targetDateInput = dateFormMaker(); // 버튼 누를 당시의 input 데이터
  container.style.display = "flex";
  messageContainer.style.display = "none";
  setClearInterval(); // 버튼을 다시 누르면 기존에 존재하던 인터벌을 삭제한다.
  counterMaker(targetDateInput); // 버튼을 누르자마자 함수를 실행시킨다.
  // 카운터 작동 - 1초마다 counterMaker 함수를 실행시킨다.
  const intervalId = setInterval(() => {
    counterMaker(targetDateInput);
  }, 1000); // 인터벌마다 고유한 id값을 가진다 / 인자가 있는 함수를 받을 때는 익명함수가 필요하다.
  intervalIdArr.push(intervalId);
};

// 타이머 초기화
const setClearInterval = function () {
  localStorage.removeItem("saved-date");
  for (let i = 0; i < intervalIdArr.length; i++) {
    clearInterval(intervalIdArr[i]);
  }
};

const resetTimer = function () {
  container.style.display = "none";
  messageContainer.style.display = "flex";
  messageContainer.innerHTML = "<h3>D-Day를 입력해 주세요.</h3>";
  setClearInterval();
};

// 화면이 실행되자마자 local stage의 데이터 유무를 파악한다. (truthy한 데이터)
if (savedDate) {
  starter(savedDate);
} else {
  container.style.display = "none";
  messageContainer.innerHTML = "<h3>유효한 시간대가 아닙니다.</h3>";
}

1) remainingObj객체에 remaining 변수들을 넣어준다. (코드 효율성을 위해 객체로 변경)

2) 반복문으로 변화하는 타이머의 숫자를 만들어 준다.

  • span태그의 id 값들을 documentArr 배열에 담아준다.
  • Object.keys로 remainingObj의 키 값들(remaining 변수들)을 timeKeys 변수에 담아준다.
  • 남은 시간이 한 자리수라면, 0을 붙이도록 조건문을 작성하여 format함수를 만든다.
  • for of 문으로 documentArr 배열에 반복문을 사용하고, remainingTime이라는 변수에
    format(remainingObj[timeKeys[i]]) 를 넣어준다.
  • document.getElementById(tag).text.Content = remainingTime 선언해준다.

3) 버튼 클릭 시 타이머가 시작되도록 starter 함수를 만들어준다.

  • container태그의 display를 flex로 변경하여 화면에 보이게 하고, messageContainer는 none으로 보이지 않게 만들어준다.
  • counterMaker()함수를 넣어 타이머가 시작되도록 한다.

4) 잘못된 값, 이미 지난 시간을 넣었을 때 메세지가 보여지도록 counterMaker 함수에서 messageContainer의 display 값을 flex로 변경하여 나타나도록 해준다. container(시간대)의 display는 none으로 바꾸어 나타나지 않도록 해준다.

  • 잘못된 값, 이미 지난 시간을 넣었을 때 아래 코드가 실행되지 않도록 조건문을 return하여 함수를 종료해준다.

5) 카운트 다운을 실행하기 위해 setTimeout()은 한계점 만큼만 타이머가 반복하므로, setInterval()로 1초마다 코드가 반복하도록 한다.

  • setInterval로 인해 1초 뒤부터 실행되므로, counterMaker함수를 위에 작성하여 버튼을 누르자마자 함수를 실행시킬 수 있도록 해준다.

6) clearInterval()를 사용하여 타이머를 초기화시킬 수 있도록 해준다.
(시작 버튼을 누를때마다 인터벌이 실행되므로 반복되는 인터벌을 제거해주어야 한다.)

  • setClearInterval 함수를 만들어 타이머 초기화 버튼에 연결시켜 준다.
    setInterval()은 실행될 때 마다 인터벌마다 고유한 id값을 가진다. intervalId 변수에 id값들을 담아준다.
  • intervalIdArr 배열을 만들어 intervalId 데이터들을 push해준다. (이때, intervalIdArr 배열은 counterMaker 함수 밖에 작성해준다.)
  • setClearInterval 함수를 만들고, 반복문으로 intervalId 배열의 id값들을 clearInterval함수에 넣어 인터벌들을 삭제한다.

7) 이미 지난 시간, 유효하지 않은 시간을 넣었을 경우에도 인터벌이 반복되므로, setclearInterval함수를 적용시켜 준다.

8) resetTimer함수를 만들어 타이머 초기화 버튼을 누르면 메세지를 다시 보여주고, 타이머 부분은 보이지 않도록 해준다.

  • setClearInterval함수를 넣어 타이머를 초기화시킨다.
  • 타이머 초기화 버튼에 resetTimer함수를 onclick으로 적용시켜 준다.

9) 카운트다운 시작 버튼을 누르지 않았는데도 입력된 값을 변경하면 카운트 다운이 새로 시작되는 것을 막아준다. (input 데이터를 매번 가져오기 때문이다.)

  • setInterval함수에 의해 counterMaker함수가 1초마다 반복 실행 되고, dateFormMaker함수(input데이터의 문자열 데이터를 받은 함수)도 반복 실행되기 때문이다.

  • 시작 버튼을 눌렀을 때만 input를 가져오도록 해준다. (starter함수 내부에 targetDateInput변수를 넣어준다.)

  • counterMaker함수의 매개변수로 data를 넣어주고, starter함수에서 실행되는 counterMaker함수에 전달인자로 targetDateInput 변수를 넣어준다.

  • new Date로 받는 데이터도 data로 바꾸어 준다.

  • setInterval함수안에 있는 counterMaker 함수에도 전달인자로 targetDateInput을 넣어준다. (이때 setInterval은 적용하려는 함수에 전달인자가 있을 경우, 화살표 함수를 이용하여 익명함수 안에 작성해야 한다.)

10) 카운트다운 시작 버튼을 누를때마다 기존에 존재하던 인터벌을 삭제하고, 새로운 input 데이터를 기반으로 인터벌이 시작되도록 한다.

  • starter함수 내에 setClearInterval 함수를 작성해 준다.

11) 페이지를 새로고침을 하여도 타이머가 종료되지 않도록 해주어야 한다.

  • Local storage에 저장된 targetDateInput 데이터를 가져온다.
    localStorage.setItem("saved-date", targetDateInput);
  • localStorage.getItem("saved-date"); 가져오고 싶은 데이터의 key를 입력하면 데이터를 가져올 수 있다. 이를 savedDate 변수에 담아준다.
  • 최초 화면이 실행될때, local storage에 데이터 유무를 파악할 수 있도록 조건문을 작성한다.
    if 뒤에는 truthy한 경우에도 조건식이 성립된다. (truthy: 데이터가 존재한다.)
  • stater함수의 매개변수로 targetDateInput을 넣어주고, 조건문으로 tragetDateInput이 undefined라면(데이터가 존재하지 않는다면), targetDateInput에 dateFormMaker함수를 재할당해준다.

12) 타이머 초기화 / 타이머 종료 / 잘못된 날짜 입력 / 인 경우 local storage의 저장된 데이터를 삭제하여 타이머를 완벽하게 초기화 해준다.

  • setClearInterval 함수에서 localStorage.removeItem("saved-date") 해준다.

13) counterMaker를 실행할 때 마다 setItem을 적용하도록 해야하는데, 이때 조건문으로 input데이터와 savedDate가 다를때만 (새로운 데이터가 들어올 때만) local storage에 저장해도록 해준다.



오늘의 회고

D-day 카운터 만들기...이런 간단해 보이는 화면에도 여러가지 기능들과 함수들이 사용되다니..
갑자기 개발자들에게 존경심이 느껴진다.. 오늘 실습하면서 엄청 많이 배운것 같은데, 주말동안 무조건 복습해야겠다.

기능을 구현하면서 중간중간 콘솔로 확인해주는 과정이 필수인것 같다. 잘 작동되는것 같다가도 어딘가 다른 부분에서 오류가 발생하거나, 작동은 되는데 어색한 부분이 있다거나 할때 콘솔로 확인하면 해결에 대한 답을 찾을 수 있는것 같다.

profile
프론트엔드 개발자 도전기

0개의 댓글