상세 컨텐츠

본문 제목

[리액트 스타터2] 2장. 자바스크립트 실전

23-24/React.js 2

by YUZ 유즈 2023. 10. 6. 10:00

본문

728x90

 

1. 구조 분해 할당

  • 배열이나 객체에서 요소를 해체해 개별 변수에 그 값을 담을 때 사용한다.

 
< 배열의 구조 분해 할당 >

let arr = [1, 2, 3];

let one = arr[0];
let two = arr[1];
let three = arr[2];

console.log(one, two, three); // 1 2 3
let arr = [1, 2, 3];
let [one, two, three] = arr; ①

console.log(one, two, three); // 1 2 3

위는 배열의 구조 분해 할당한 예이다.

let arr = [1, 2, 3];
let [one, two] = arr;

console.log(one, two); // 1 2
  • 배열의 길이와 할당할 변수의 개수가 일치하지 않아도 오류가 발생하지 않는다.
let arr = [1, 2];
let [one, two, three] = arr;

console.log(one, two, three); // 1 2 undefiend
  • 할당할 변수의 개수가 배열의 길이보다 많아도 오류가 발생하지 않는다.
  • 다만 배열의 길이를 넘는 변수에는 undefined가 할당된다.
     

 
< 객체의 구조 분해 할당 >

let person = {
  name: "이정환",
  age: 25,
  location: "경기도"
};

let { name, age, location } = person;

console.log(name, age, location);

// 이정환 25 경기도
  • 데이터 저장 순서가 아니라 key를 기준으로 할당된다.

 
 
< 함수의 매개변수가 객체일 때 구조 분해 할당하기 >

function func({ name, age, location }) {
  console.log(name, age, location);
}

let person = {
  name: "이정환",
  age: 25,
  location: "경기도"
};

func(person);

// 이정환 25 경기도
function func({ name: n, age: a, location: l }) {
  console.log(n, a, l);
}

let person = {
  name: "이정환",
  age: 25,
  location: "경기도"
};

func(person);

// 이정환 25 경기도
  • 객체의 구조 분해 할당 과정에서 매개변수의 이름을 새롭게 바꿀 수 있다.
  • 변수 이름 옆에 콜론:과 함께 새 변수명을 쓰면, 새 이름으로 값이 할당된다.

 


 

2. 스프레드 연산자와 rest 매개변수

 

  • 스프레드 연산자: 개별 요소로 분리한다.
  • rest 매개변수: 개별 요소를 다시 배열로 묶는다.

 
 

< 스프레드 연산자 >

  • 스프레드 연산자(전개 연산자): 기호 ‘...’로 표기한다.
  • 반복이 가능한 객체의 값을 개별 요소로 분리한다.
let arrA = [1, 2, 3];
let arrB = [...arrA, 4, 5, 6];

console.log(arrB); // [1, 2, 3, 4, 5, 6]
  • 만약 arrB = [arrA, 4, 5, 6]이라면 arrB에는 [[1, 2, 3], 4, 5, 6]이 저장된다.
     

다음은 객체를 다룬 예제이다.

let objA = {
  a: 1,
  b: 2
};

let objB = {
  ...objA,
  c: 3,
  d: 4
};

console.log(objB); // {a: 1, b: 2, c: 3, d: 4}

 
 
< 스프레드 연산자와 함수 >

function func(a, b, c) {
  console.log(a, b, c);
}

let arr = [1, 2, 3];
func(...arr); ① // 1 2 3

 
 
< 매개변수에서 구조 분해 할당과 스프레드 연산자의 차이 >

  • 구조 분해 할당: 함수를 호출할 때 전달하는 인수가 1개이고 그 값이 객체인 경우이다.
  • 스프레드 연산자: 인수가 1개가 아닌 여러 개로 나뉘어 전달된다. 따라서 매개변수 역시 여러 개 선언한다.

 
 

< rest 매개변수 >

  • 나머지 매개변수라고 한다.
  • 기호 ‘...’으로 표기한다.
  • 매개변수로 사용할 변수의 이름 앞에 ... 을 붙이면 rest 매개변수가 된다.
  • 스프레드 연산자와 반대로 개별 요소를 배열로 묶는다.
function func(param, ...rest) {
  console.log(param);
  console.log(rest);
}

func(1, 2, 3, 4);

// 1
// [2, 3, 4]
  • 매개변수 param에는 첫 번째 인수 1이, 나머지 인수들은 순차적으로 변수 rest에 배열로 할당된다.
function func(...rest, param) { // 오류 : rest 매개변수는 마지막에 작성해야 합니다.
  console.log(param);
  console.log(rest);
}

func(1, 2, 3, 4);
  • rest 매개변수는 먼저 선언한 매개변수에 할당된 인수를 제외하고 나머지를 모두 배열에 저장한다. 따라서 반드시 매개변수에서 마지막에 선언되어야 한다.

 

3. 배열과 메서드

 
 

{ 요소의 추가 및 삭제 메서드 }

 

< push >

  • 배열 맨 끝에 요소를 추가하고 새로운 길이를 반환한다.
  • 무조건 배열 맨 끝에 요소를 추가한다.
  • 여러 요소를 추가하려면 콤마로 구분해 전달하면 된다.
let food = ["짜장면", "피자", "치킨"];
const newLength = food.push("탕수육", "라자냐");

console.log(food); // ["짜장면", "피자", "치킨", "탕수육", "라자냐"]
console.log(`새로운 배열의 길이: ${newLength}`); // 새로운 배열의 길이: 5

 
< pop >

  • 배열의 맨 끝 요소를 제거하고, 제거한 요소를 반환한다.
let food = ["짜장면", "피자", "치킨"];
const removedItem = food.pop(); // ①

console.log(removedItem); // 치킨
console.log(food); // ["짜장면", "피자"]
let food = [];
const removedItem = food.pop();

console.log(removedItem); // undefined
console.log(food); // []
  • 빈 배열에서 pop 메서드를 사용하면, 제거할 요소가 없기 때문에 undefined를 반환한다.

 
< shift >

  • pop 메서드와 반대로 배열의 맨 앞 요소를 제거하고, 제거한 요소를 반환한다.
let food = ["짜장면", "피자", "치킨"];
const removedItem = food.shift(); // ①

console.log(removedItem); // "짜장면"
console.log(food); // ["피자", "치킨"]

 
< unshift >

  • push와 반대로 배열 맨 앞에 요소를 추가하고, 새 배열의 길이를 반환한다.
let food = ["짜장면", "피자", "치킨"];
const newLength = food.unshift("갈비찜"); // ①

console.log(food); // ["갈비찜", "짜장면", "피자", "치킨"]
console.log(`새로운 배열의 길이: ${newLength}`); // 새로운 배열의 길이: 4

 
< shift와 unshift는 push나 pop보다 느리다 >

  • unshift 메서드로 배열 맨 앞에 요소를 추가할 경우, 새 요소가 인덱스 0이 되어 나머지 배열 요소의 인덱스는 모두 하나씩 뒤로 밀린다.
  • 반면 push나 pop 메서드는 배열의 마지막 요소를 추가 또는 제거하는 것이므로 기존 요소들의 인덱스는 변함이 없다.

 

< slice >

  • 기존 배열에서 특정 범위를 잘라 새로운 배열을 반환한다.
  • 원본 배열은 수정되지 않는다는 점에 유의하자.
arr.slice(start, end);
  • start는 잘라낼 범위의 시작, end는 잘라낼 범위의 끝이다.
  • 주의할 점은 end로 범위의 끝을 지정하면, 그 범위는 end 인덱스 전까지이다.
const arr = [1, 2, 3];
const sliced = arr.slice(2); ①

console.log(sliced); // [3]
  • start만 전달하고 end를 전달하지 않으면, start부터 배열 끝까지 잘라낸 새 배열을 반환한다.
const arr = [1, 2, 3, 4, 5];

console.log(arr.slice(-1)); ① // [5]
console.log(arr.slice(-2)); // [4, 5]
console.log(arr.slice(-3)); // [3, 4, 5]
console.log(arr.slice(-4)); // [2, 3, 4, 5]
console.log(arr.slice(-5)); // [1, 2, 3, 4, 5]
  • 음숫값을 인덱스로 전달해도 된다.
  • 만약 end 없이 start만 음수 인덱스로 전달하면, 배열 맨 끝부터 전달한 음수의 절댓값만큼 잘라낸 새 배열을 반환한다.
  • 뒤에서부터 셀 때는 -1이 첫 번째 인덱스 번호이다.

 
< concat >

  • 서로 다른 배열을 이어 붙여 새 배열을 반환한다.
  • silce 메서드와 같이 원본 배열을 수정하지 않는다.

 

let arrA = [1, 2];
let arrB = [3, 4];
let arrC = arrA.concat(arrB); ① // 

console.log(arrC);    // [1, 2, 3, 4]
console.log(arrA); ② // [1, 2]

인수로 배열이 아닌 객체를 전달해 보자.

let arrA = [1, 2];
let arrB = { a: 1, b: 2 };
let arrC = arrA.concat(arrB);

console.log(arrC); // [1, 2, { a: 1, b: 2 } ]
  • 인수로 배열을 전달하면 요소를 모두 이어 붙이지만, 객체는 하나의 요소로 인식해 삽입된다.
     

 

{ 순회 메서드 }
 

< forEach >

  • 배열의 모든 요소에 순서대로 접근해 특정 동작을 수행한다.
  • 인수로 함수를 요구한다.
  • 콜백 함수 : 함수 호출 과정에서 인수로 전달되는 함수이다.
  • forEach 메서드는 배열 요소 각각을 순회하면서, 인수로 전달한 콜백 함수가 정의한 대로 요소를 동작시킨다.
function cb(item, index, array) {
  // 요소에 무언가를 할 수 있습니다.
}

arr.forEach(cb);
  • item: 현재 순회하는 배열 요소 
  • idx: 현재 순회하는 배열 요소의 인덱스
  • arr: 순회 중인 배열
function cb(item, idx) {// ②
  console.log(`${idx}번째 요소: ${item}`);
}

const arr = [1, 2, 3];
arr.forEach(cb); // ①

// 0번째 요소: 1 
// 1번째 요소: 2 
// 2번째 요소: 3
  • cb는 총 3번 실행된다.

 

  • 함수 표현식이나 화살표 함수로 간략하게 표현할 수 있다.
  • 화살표 함수는 앞선 예제의 함수 cb와 동일한 역할을 한다.
const arr = [1, 2, 3];

arr.forEach((item, idx) => { ①
  console.log(`${idx}번째 요소: ${item}`);
});

// 0번째 요소: 1
// 1번째 요소: 2
// 2번째 요소: 3

 
 
{ 탐색 메서드 }
 

< indexOf >

  • 배열에서 찾으려는 요소의 인덱스를 반환한다.
arr.indexOf(item, fromIndex);
  • item: 찾으려는 요솟값
  • fromIndex: 탐색을 시작할 인덱스 번호
  • formIndex 생략하면 배열의 0번째 인덱스부터 탐색한다.
     
  • fromIndex의 값을 음수로 지정할 수 있는데, 그러면 탐색 위치는 배열의 맨 뒤에서부터 시작한다.
let arr = [1, 3, 5, 7, 1];

console.log(arr.indexOf(1)); // ① 0
console.log(arr.indexOf(1, -1)); // ② 4
  • 찾으려는 요소가 배열에 없다면 -1을 반환한다.
  • fromIndex의 값이 배열의 길이보다 크거나 같은 경우에도 -1을 반환한다.

 

  • indexOf는 엄격한 비교 연산자(===)로 요소를 비교하므로 자료형이 다르면 다른 값으로 평가한다.
let arr = [1, 3, 5, 7, 1];

console.log(arr.indexOf("3")); // -1
  • 객체는 탐색할 수 없다. 객체 자료형은 값을 비교하는 게 아니라 참조값을 비교하기 때문이다.
let arr = [{ name: "이정환" }, 1, 2, 3];

console.log(arr.indexOf({ name: "이정환" })); // -1

 
< includes >

  • 배열에 특정 요소가 있는지 판별한다.
let arr = [1, 3, 5, 7, 1];

console.log(arr.includes(3)); // true
console.log(arr.includes("생선")); // false

 
< findIndex >

  • indexOf처럼 배열에서 찾으려는 요소의 인덱스 번호를 찾아 반환한다.
arr.findIndex( callback(item, index, array) );
  • indexOf와는 달리 인수로 콜백 함수를 전달하는데, 이 함수를 ‘판별 함수’라고 한다.
  • 배열에서 이 판별 함수를 만족하는 첫 번째 요소의 인덱스를 반환하며, 그런 요소가 없다면 -1을 반환한다.
  • 판별 함수에는 3개의 매개변수(현재요소 item, 현재 인덱스 index, 탐색 대상 배열 array)가 제공된다.

 

function determine(item, idx, arr) { ②
  if (item % 2 === 0) {
    return true;
  } else {
    return false;
  }
}

let arr = [1, 3, 5, 6, 8];
let index = arr.findIndex(determine); ①

console.log(index); // 3
  • findIndex 메서드가 true를 반환하면 탐색에 성공한 것이므로 탐색을 멈춘다.
  • 배열 arr에서 처음으로 짝숫값이 나오는 인덱스 번호 3을 반환한다.

 
다음은 화살표와 삼항 연산자를 이용하여 간결하게 작성한 경우이다.

let arr = [1, 3, 5, 6, 8];
let index = arr.findIndex((item) =>
  item % 2 === 0 ? true : false
);

console.log(index); // 3

 

  • 이번에는 findIndex로 배열에서 프로퍼티 name의 값이 “이정환”인 요소의 인덱스 번호를 찾아보겠다.
  • indexOf와 달리, findIndex는 판별 함수를 이용해 배열에서 조건과 일치하는 객체 요소를 찾아낸다.
let arr = [
  { name: "이종원" },
  { name: "이정환" },
  { name: "신다민" },
  { name: "김효빈" }
];

let index = arr.findIndex((item) => item.name === "이정환"); ①
console.log(index); // 1

 
< find >

  • findIndex처럼 판별 함수를 전달하고, 배열에서 이를 만족하는 요소를 찾는다.
  • 다만 findIndex와 달리 인덱스가 아닌 요소를 반환한다.
let arr = [
  { name: "이종원" },
  { name: "이정환" },
  { name: "신다민" },
  { name: "김효빈" }
];

let element = arr.find((item) => item.name === "이정환"); ①
console.log(element); // {name: "이정환"}

 
 
 
< filter >

  • 배열에서 조건을 만족하는 요소만 모아 새로운 배열로 반환한다.
let arr = [
  { name: "이종원", hobby: "축구" },
  { name: "이정환", hobby: "영화" },
  { name: "신다민", hobby: "축구" },
  { name: "김효빈", hobby: "노래" }
];

let filteredArr = arr.filter(
  (item) => item.hobby === "축구"
);

console.log(filteredArr);

// 출력 결과
// (2) [Object, Object]
// 0: Object
// name: "이종원"
// hobby: "축구"
// 1: Object
// name: "신다민"
// hobby: "축구"

 
 
{ 변형 메서스 }
 

< map > 

  • 배열 각각의 요소에 대한 함수 호출 결과를 모아 새 배열을 만들어 반환한다.
arr.map( callback(item, index, array) );
  • map 메서드는 콜백 함수를 인수로 전달한다. 이 콜백 함수에는 현재 요소 item, 인덱스 index, map 메서드를 호출한 배열 array이 매개변수로 제공된다.
let arr = [1, 2, 3, 4];
let newArr = arr.map((item) => item * 3); // ①

console.log(newArr); // [3, 6, 9, 12]
  • newArr에는 배열 arr의 모든 요소에 3을 곱한 결과가 저장된다.

 

let arr = [
  { name: "이종원", hobby: "축구" },
  { name: "이정환", hobby: "영화" },
  { name: "신다민", hobby: "축구" },
  { name: "김효빈", hobby: "노래" }
];

let newArr = arr.map((item) => item.name);

console.log(newArr);
  • newArr에는 기존 arr에서 사람 이름만 따로 모은 배열이 저장된다.

 
< sort >

  • 배열의 요소를 정렬한다.
  • 정렬된 새로운 배열을 반환하는 게 아니라, 기존 배열 요소를 다시 정렬한다는 점에 주의하자.
arr.sort( compare( a, b ) )
  • sort 메서드에서는 하나의 콜백 함수를 인수로 전달한다. 이 함수는 비교 함수로 사용되는데, 필수 사항은 아니다.
let arr = [10, 5, 3];
arr.sort();

console.log(arr); // [10, 3, 5]
  • 잘못된 결과가 나온 이유는 sort 메서드가 기본적으로 요소를 문자열로 취급해 사전순으로 정렬하기 때문이다.
    -> 비교함수 사용하자
function compare(a, b) {
  if (a > b) {
    return 1;
  } else if (a < b) {
    return -1;
  } else {
    return 0;
  }
}

let arr = [10, 5, 3];
arr.sort(compare);

console.log(arr); // [3, 5, 10]
  •  
  • 비교 함수가 양수를 반환 a와 b 중 b의 위치가 a보다 앞이어야 한다는 것을 의미한다. 
  • 비교 함수가 음수를 반환 a와 b 중 a의 위치가 b보다 앞이어야 한다는 것을 의미한다. 
  • 비교 함수가 0을 반환 비교 함수가 0을 반환하면, a와 b는 정렬 순서가 동일하다는 것을 의미한다.

 
< join >

  • 배열 요소를 모두 연결해 하나의 문자열로 반환한다.
let arr = ["안녕", "나는", "이정환"];

console.log(arr.join()); // ① 안녕,나는,이정환
console.log(arr.join("-")); // ② 안녕-나는-이정환

 
< reduce >

  • 배열 요소를 모두 순회하면서 인수로 제공한 함수를 실행하고, 단 하나의 결괏값만 반환한다.
  • map 메서드와 유사하지만 하나의 결과만을 반환한다는 차이가 있다.
arr.reduce( ( acc, item, index, array ) => {
  (...)
}, initial );
  • 호출할 때 2개의 인수 (콜백 함수,  초깃값)을 전달한다.
  • 첫 번째 인수로 전달하는 콜백 함수를 특별히 ‘리듀서’라고 부른다. 리듀서 함수는 배열의 모든 요소에 대해 각각 실행되는데, 4개의 매개변수를 제공받는다.
  • 리듀서에 제공되는 매개변수의 역할은 다음과 같다.
    • acc: 누산기(accumulator)라는 뜻으로 이전 함수의 호출 결과를 저장한다. reduce 메서드의 두 번째 인수 initial이 이 acc의 초깃값이 된다.
    • item: 현재의 배열 요소이다.
    • index: 현재의 배열 인덱스이다.
    • array: reduce 메서드를 호출한 배열이다.
    • acc의 초깃값인 인수 initial은 필수 사항은 아니며, 전달하지 않으면 배열의 첫 번째 요소가 acc의 초깃값이 된다.

let arr = [1, 2, 3, 4, 5];
let result = arr.reduce((acc, item) => acc + item, 0);

console.log(result); // 15

reduce의 동작 과정


 

4. Date 객체와 날짜


< date  객체 생성하기 >

let date = new Date();
console.log(date);
// 현재 날짜 및 시간

생성자: 자바스크립트의 생성자는 객체를 생성하는 함수이다. Date 객체는 리터럴이 아닌 생성자로 만든다. 생성자로 객체를 만들 때 특정 시간 등의 정보를 인수로 전달하면, 객체를 생성함과 동시에 초기화할 수 있다.
 
< 협정 세계시 > 
시간의 시작을 1970년 1월 1일 0시 0분 0초를 기준으로 하며, 이 시작 시각을 UTC+0시라고 표현한다.

let Jan01_1970 = new Date(0);
console.log(Jan01_1970);

// Thu Jan 01 1970 09:00:00 GMT+0900 (한국 표준시)

 1970년 1월 1일 9시 0분 0초로 출력되는 것을 볼 수 있는데, 이는 한국 표준시가 UTC보다 9시간이 빠르기 때문이다.

< 타임스탬프 >
특정 시간이 UTC+0시인 1970년 첫날을 기준으로 흘러간 밀리초(ms)의 시간을 의미한다.
24시간에 해당하는 밀리초를 인수로 전달하면, UTC+0에서 하루가 지난 값을 반환한다.
하루에 해당하는 밀리초는 24 * 3600 * 1000이다.
 
다음과 같이 생성된 Date 객체에서 역으로 타임스탬프를 구할 수도 있다.

let Jan02_1970 = new Date(24 * 3600 * 1000);
console.log(Jan02_1970.getTime());
// 86400000

 


{ 원하는 날짜로 Date 객체 생성하기 }

 
< 문자열로 특정 날짜 전달하기 >
다음 4개의 Date 객체 생성자에 인수로 전달하는 날짜는 각각 다른 형식의 문자열이다.

let date1 = new Date("2000-10-10/00:00:00"); ①
let date2 = new Date("2000.10.10/00:00:00"); ②
let date3 = new Date("2000/10/10/00:00:00"); ③
let date4 = new Date("2000 10 10/00:00:00"); ④

console.log("1:", date1); // 1: Tue Oct 10 2000 00:00:00 GMT+0900 (한국 표준시)
console.log("2:", date2); // 2: Tue Oct 10 2000 00:00:00 GMT+0900 (한국 표준시)
console.log("3:", date3); // 3: Tue Oct 10 2000 00:00:00 GMT+0900 (한국 표준시)
console.log("4:", date4); // 4: Tue Oct 10 2000 00:00:00 GMT+0900 (한국 표준시)

 
< 숫자로 특정 날짜 전달하기 >
year, month, date, hours, minutes, seconds, milliseconds 순서이다.

let date1 = new Date(2000, 10, 10, 0, 0, 0, 0);
let date2 = new Date(2000, 9, 10);

console.log("1:", date1); // 1: Fri Nov 10 2000 00:00:00 GMT+0900 (한국 표준시)
console.log("2:", date2); // 2: Tue Oct 10 2000 00:00:00 GMT+0900 (한국 표준시)

Date 객체가 해당 월의 시작을 1이 아니라 0부터 시작하기 때문에 1월은 0, 12월은 11로 전달해야 원하는 출력 결과를 얻을 수 있다.
 
 
< 타임스탬프로 날짜 생성하기 >
문자열이나 객체보다 저장 공간을 훨씬 적게 차지하여 빠른 비교와 탐색이 가능하다.

let date = new Date(2000, 9, 10);
let timeStamp = date.getTime(); // ①
console.log(timeStamp); // 971103600000

let dateClone = new Date(timeStamp); // ②
console.log(dateClone); // Tue Oct 10 2000 00:00:00 GMT+0900 (한국 표준시)

 
 
{ Date 객체에서 날짜 요소 얻기 }

 
< getFullYear >

  • getYear 메서드는 사용하지 않는다.
let date = new Date(2000, 9, 10);

console.log(date.getFullYear()); // 2000

 
< getMonth >

let date = new Date(2000, 9, 10);

console.log(date.getMonth()); // 9
  • 월을 0부터 11까지 사이의 숫자로 반환하면서 표기는 1월부터 12월로 하니 주의하자.

 
< getDate >

let date = new Date(2000, 9, 10);

console.log(date.getDate()); // 10

 
< getDay >

  • 0부터 6으로 표현되는 요일을 반환한다. 0은 항상 일요일이며, 6은 토요일이다.
let date = new Date(2000, 9, 10);

console.log(date.getDay()); // 2

 
< getHours, getMinutes, getSeconds, getMilliseconds >

  • 각각 시간, 분, 초, 밀리초를 반환한다.

 
 

{ Date 객체의 날짜 요소 수정하기 }
 

< setFullYear >

  • Date 객체의 연도를 수정할 때 사용한다.
let date = new Date(2000, 9, 10);
date.setFullYear(2021);

console.log(date); // Sun Oct 10 2021 00:00:00 GMT+0900 (한국 표준시)

 
< setMonth>

  • 객체의 월을 수정할 때 사용한다.

 
< setDate >

  • 객체의 일을 수정할 때 사용한다.

 
< setHours, setMinutes, setSeconds >

  • 각각 시, 분, 초를 수정할 때 사용한다.
let date = new Date(2000, 9, 10);

date.setHours(1);
date.setMinutes(1);
date.setSeconds(1);

console.log(date); // Tue Oct 10 2000 01:01:01 GMT+0900 (한국 표준시)

 
 

{ Date 객체 출력하기 }
 

< toSrting >

  • 현재 저장된 시간을 문자열로 반환한다.
  • 콘솔에 출력했을 때와 동일한 형태의 문자열이 출력된다.
const today = new Date(2000, 9, 10, 22);

console.log(today.toString()); // Tue Oct 10 2000 22:00:00 GMT+0900 (한국 표준시)

 
< toDateString >

  • 현재의 날짜만 출력하는 메서드이다.

 
< toLocaleString, toLocaleDateString >

  • 현재 우리가 속한 시간대에 맞게 변환된 날짜와 시간을 반환한다.
  • 한국은 Asia/Seoul 시간대에 속하기 때문에 ‘오후’처럼 현지화된 반환값을 볼 수 있다.
  • toLocaleString은 날짜와 시간 모두 반환하고, toLocaleDateString은 날짜만 반환한다.
const today = new Date(2000, 9, 10, 22);

console.log(today.toLocaleString()); // 2000. 10. 10. 오후 10:00:00
console.log(today.toLocaleDateString()); // 2000. 10. 10.

 
 

{ Date 객체 응용하기 }
 

< n월씩 이동하기 >

function moveMonth(date, moveMonth) { // ①
  const curTimestamp = date.getTime(); // ②
  const curMonth = date.getMonth(); // ③

  const resDate = new Date(curTimestamp); // ④
  resDate.setMonth(curMonth + moveMonth); //⑤

  return resDate;
}

const dateA = new Date("2000-10-10");
console.log("A: ", dateA); // A : Tue Oct 10 2000 09:00:00 GMT+0900 (한국 표준시)

const dateB = moveMonth(dateA, 1);
console.log("B: ", dateB); // B : Fri Nov 10 2000 09:00:00 GMT+0900 (한국 표준시)

const dateC = moveMonth(dateA, -1);
console.log("C: ", dateC); // C : Sun Sep 10 2000 09:00:00 GMT+0900 (한국 표준시)

변수 resDate를 만들고 새로운 Date 객체를 생성합니다. Date 객체를 만들면서 에서 구한 타 임 스탬프값(curTimestamp)을 인수로 전달합니다. 결과적으로 변수 resDate에는 date 객체와 동일한 타임스탬프값이 들어 있는 Date 객체가 저장됩니다. 
변수 resDate에 저장된 Date 객체에서 setMonth 메서드를 호출해 기존 월에 moveMonth만큼 더 한 월을 새로운 월로 저장합니다. 결론적으로 이 함수를 호출하면 moveMonth만큼 월을 앞으로 또는 뒤로 이동시킵니다.
 
< 배열에서 이번 달에 해당하는 날짜만 필터링하기 >

function filterThisMonth(pivotDate, dateArray) {  // ①
  const year = pivotDate.getFullYear();
  const month = pivotDate.getMonth();

  const startDay = new Date(year, month, 1, 0, 0, 0, 0); // ②
  const endDay = new Date(year, month + 1, 0, 23, 59, 59); // ③

  const resArr = dateArray.filter(
    (it) =>
      startDay.getTime() <= it.getTime() && // ④
      it.getTime() <= endDay.getTime()
  );
  return resArr;
}

const dateArray = [
  new Date("2000-10-1"),
  new Date("2000-10-31"),
  new Date("2000-11-1"),
  new Date("2000-9-30"),
  new Date("1900-10-11")
];

const today = new Date("2000-10-10/00:00:00"); // 오늘은 2000년 10월 10일이라고 가정합니다.
const filteredArray = filterThisMonth(today, dateArray);

console.log(filteredArray);

// 0: Sun Oct 01 2000 00:00:00 GMT+0900 (한국 표준시)
// 1: Tue Oct 31 2000 00:00:00 GMT+0900 (한국 표준시)

이번 달의 가장 늦은 시간은 다음 달 0일의 23시 59분 59초(이번 달의 가장 마지막 날을 의미)로 설정해 구합니다. 
filter 메서드를 이용해 dateArray에서 이번 달에 속하는 요소만 필터링합니다. 서로 다른 Date 객체를 비교할 때는 getTime 메서드로 타임스탬프를 기준으로 비교합니다. 특정 Date 객체가 더 크다는 것은 이 객체가 더 미래에 있는 시간이라는 뜻입니다.
 

  • 이번 달에 해당하는 날짜가 있는 Date 객체를 필터링하기 위해서는 다음과 같이 2가지 작업이 필요하다.
    • 이번 달에서 가장 빠른 시간, 가장 늦은 시간 구하기
    • 1번에서 구한 시간 내에 포함되는 Date 객체를 필터링하기

 
Q. 왜 이달의 가장 늦은 시간이 다음 달 0일 23시 59분 59초일까?
Date 객체에서 date 즉 일을 0으로 설정하면 해당 월 바로 이전 월의 마지막 날을 의미한다. 즉 2000년 10월 0일은 2000년 9월의 마지막 날이다.
 
 
 
 

5. 비동기 처리

  • 오래 걸리는 작업이 종료될 때까지 기다리지 않고 다음 작업을 수행한다.

 
 
< 동기와 비동기 >

  • 동기: 순차적으로 코드를 실행하는 것
  • 비동기: 특정 작업을 다른 작업과 관계없이 독립적으로 동작하게 만드는 것

 

  • 비동기 작업을 위해 함수 setTimeout을 이용한다.
setTimeout(function () { ①
  console.log("1번!"); 
}, 3000);

console.log("2번!");

// 2번!
// 1번!

함수 setTimeout은 두 번째 인수로 전달된 시간(밀리초)만큼 기다린 다음, 첫 번째 인수로 전달 한 콜백 함수를 실행합니다. 따라서 이 코드에서는 3초(3000밀리 초)만큼 기다린 다음 콜백 함수를 실행합니다.
 
다음과 같이 화살표 함수를 이용하면 더 간결하게 작성할 수 있다.

setTimeout(() => { ①
  console.log("1번!");
}, 3000);

console.log("2번!"); ②

// 2번!
// 1번!
function orderCoffee(coffee, time) { ①
  setTimeout(() => {
    console.log(`${coffee} 제조 완료`);
  }, time);
}

orderCoffee("달콤한 커피", 4000);
orderCoffee("레몬 티", 2000);
orderCoffee("시원한 커피", 3000);

// 레몬 티 제조 완료 
// 시원한 커피 제조 완료 
// 달콤한 커피 제조 완료

 
< 콜백 함수로 비동기 처리하기 >
 
다음 예제의 함수 double은 1초를 기다린 다음 전달한 인수에 2를 곱해 콘솔에 출력한다.

function double(num) {
  setTimeout(() => {
    const doubleNum = num * 2;
    console.log(doubleNum);
  }, 1000);
}

double(10); // 20

만약 함수 double의 결과를 반환하게 하려면 어떻게 해야 할까?

function double(num) {
  return setTimeout(() => {
    const doubleNum = num * 2;
    return doubleNum; ①
  }, 1000);
}

const res = double(10);
console.log(res);

// 알 수 없는 숫자
  • 오류가 나는 이유는 반환값이 함수 setTimeout에서 인수로 전달한 콜백 함수가 반환하는 게 아니기 때문이다. 함수 setTimeout은 타이머의 식별 번호를 반환한다. 따라서 콘솔에 출력된 알 수 없는 숫자는 인수로 전달한 콜백 함수의 반환값이 아니라 타이머의 식별 번호일 뿐이다.
  • 콜백 함수는 함수 setTimeout에서 전달하는 인수일뿐이다. 따라서 콜백 함수의 반환값과 함수 setTimeout의 반환값은 무관하다.

 
다음과 같이 콜백 함수의 인수로 2를 곱한 결괏값을 전달하면, 간단하게 비동기 작업의 결괏값을 반환값으로 사용할 수 있다.

function double(num, cb) {
  setTimeout(() => {
    const doubleNum = num * 2;
    cb(doubleNum); // ②
  }, 1000);
}

double(10, (res) => {  // ①
  console.log(res);
});

console.log("마지막"); // ③

// 마지막
// 20

함수 double을 호출하며 두 번째 인수로 화살표 함수로 만든 콜백 함수를 전달합니다. 콜백 함수는 함수 double의 매개변수 cb에 저장되며, 호출되면 인수로 전달한 값을 콘솔에 출력합니다. 
비동기 작업이 완료되면 콜백 함수를 호출해 연산의 결괏값을 인수로 전달합니다. 
    -> 콜백 함수를 이용하면 비동기 작업의 결괏값을 사용할 수 있다.
 
 
< 프로미스 객체를 이용해 비동기 처리하기 >
 

  • 진행 단계 3가지 상태
    • 대기 상태: 작업을 아직 완료하지 않음
    • 성공 상태: 작업을 성공적으로 완료함
    • 실패 상태: 작업이 모종의 이유로 실패함

프로미스의 3가지 상태

 

  • 프로미스 객체 형태
const promise = new Promise(실행 함수); ①
  • 인수로 실행 함수(executor)를 전달하는데, 실행 함수란 비동기 작업을 수행하는 함수를 말한다.
const promise = new Promise(function (resolve, reject) {
  setTimeout(() => {
    console.log("안녕");
  }, 500);
});

// 안녕
  •  이 함수는 새롭게 생성된 프로미스 객체의 실행 함수이다. 프로미스 객체를 생성함과 동시에 실행되며 2개의 매개변수를 제공받는다. 프로미스 객체는 생성과 동시에 실행 함수를 실행해 콘솔에 “안녕”이라고 출력한다.

 

  • 실행 함수가 제공받는 2개의 매개변수는 다음과 같다.
    • resolve: 비동기 작업의 상태를 성공으로 바꾸는 함수
    • reject: 비동기 작업의 상태를 실패로 바꾸는 함수

 
다음은 매개변수 resolve를 호출하여 작업 상태를 성공 상태로 변경하는 예이다.

const promise = new Promise(function (resolve, reject) {
  setTimeout(() => {
    resolve("성공");
  }, 500);
});

 
 
만약 결괏값을 비동기 작업이 아닌 곳에서 이용하려면 다음과 같이 프로미스 객체의 then 메서드를 이용한다.

  • then 메서드는 인수로 전달한 콜백 함수의 비동기 작업이 성공했을 때 실행한다.
const promise = new Promise(function (resolve, reject) {
  setTimeout(() => {
    resolve("성공");
  }, 500);
});

promise.then(function (res) { ①
  console.log(res);
});

// 성공

then 메서드를 호출하고 인수로 콜백 함수를 전달합니다. 이 콜백 함수는 비동기 작업이 성공했을 때, 즉 실행 함수가 resolve를 호출했을 때 실행됩니다.
    -> 실행 함수에서 0.5초 기다린 다음 resolve를 호출하고 인수로 "성공"을 전달한다.
 

const promise = new Promise(function (resolve, reject) {
  setTimeout(() => {
    reject("실패");
  }, 500);
});

promise.then(function (res) {
  console.log(res);
});

promise.catch(function (err) { ①
  console.log(err);
});

// 실패

실행 함수에서 reject를 호출하여 이 작업이 실패했음을 알리고 인수로 “실패”를 전달합니다. 
비동기 작업이 실패했으므로 then 메서드에 인수로 전달한 콜백 함수는 실행되지 않습니다.
이때 then 메서드에 전달한 콜백 함수는 실행되지 않는다.
 
작업이 실패했을 때 실행할 콜백 함수를 설정하려면 다음과 같이 catch 메서드를 사용해야 한다.

const promise = new Promise(function (resolve, reject) {
  setTimeout(() => {
    reject("실패");
  }, 500);
});

promise.then(function (res) {
  console.log(res);
});

promise.catch(function (err) { ①
  console.log(err);
});

// 실패

-> 이처럼 프로미스의 thencatch 메서드를 이용하면 작업이 성공하거나 실패했을 때 실행할 콜백 함수를 별도로 설정할 수 있다.



 

Quiz

1. slice 메서드는 원본 배열을 수정하지 않지만, concat 메서드는 원본 배열을 수정한다. ( O / X )

2. indexOf는 자료형이 달라도 같은 값으로 평가한다. (O / X )
 
3. sort 메서드는 새로운 배열을 반환하는 것이 아니라, 기존 배열 요소를 다시 정렬한다. (O / X )
 
4. 협정 세계시에서 시간의 시작되는 순간을 말해보자.
 
5. Date 객체에서 날짜 요소 얻기에서 연도를 반환받기 위해서는 (   ) 메서드를 이용한다.
 
6. getDay 메서드에서 목요일은 숫자 몇으로 반환될까?
 
 
7. Date 객체 출력하는 메서드 중 '현지화'된 날짜와 시간을 모두 반환하는 메서드의 이름을 말해보자. 


1. 다음 코드의 결과를 말해보자.

let arr = [1, 3, 5, 7, 1];

console.log(arr.indexOf(7, 9));

 
2. reduce 메서드를 이용하여 1부터 5까지 더해지는 코드를 짜보아라.
 
 


x / x / o / 1970년 1월 1일 0시 0분 0초 / getFullYear / 4 / toLocaleString
 
-1

let arr = [1, 2, 3, 4, 5];
let result = arr.reduce((acc, item) => acc + item, 0);

console.log(result); // 15

출처: 이정환, 『한 입 크기로 잘라먹는 리액트』, 프로그래밍인사이트(2023), 2-5~2-9장.

Editor: yunseul

728x90

관련글 더보기