[JS] 9. Collection




1. 생성자

생성자 함수

// 빵틀
function FishBread(flavor, price){
    this.flavor = flavor
    this.price = price
    this.base = "flour"
}

// 붕어빵
let bread1 = new FishBread("cream", 1200)
console.log(bread1)
//FishBread { flavor: 'cream', price: 1200, base: 'flour' }
let bread2 = new FishBread("milk", 2000)
console.log(bread2)
//FishBread { flavor: 'milk', price: 2000, base: 'flour' }
let bread3 = new FishBread("redBean", 800)
console.log(bread3)
//FishBread { flavor: 'redBean', price: 800, base: 'flour' }
  • 유사한 객체를 다중으로 만들 때 사용되는 함수 (타 언어에서의 class 개념과 유사)
  • 일반적으로 생성자 함수의 첫 글자는 대문자로 시작
  • 생성자 함수로 객체 생성 시 new 연산자를 통해 객체 생성
  • 생성자 함수와 new 연산자를 통해 빠른 객체 생성 가능


new.target

function User(name){
    console.log(new.target)
    if (!new.target) {
        return new User(name)
    }
    this.name = name;
}

// 객체를 만들 때 new 를 썼는지 안썼는지 파악 가능
let result1 = User("John")
// undefined
console.log(result1)
// undefined

let result2 = new User("John")
//[Function: User]
console.log(result2)
//User { name: 'John' }
  • new.target 속성 (property)을 사용하여 new와 함께 호출했는지 확인 가능
  • 유연한 생성자 함수를 만들기 위해 new.target이 없을 때, new 키워드 추가하여 호출되도록 처리



2. Collection

  • 구조 혹은 비구조화 형태로 프로그래밍 언어가 제공하는 값을 담을 수 있는 공간
  • 내부적으로 이터레이터가 있다 (반복문)
  • js 에서 제공하는 collection
  • Indexed Collection : Array, Typed Array
  • Keyed Collection : Object, Map, Weak Map, Set, Weak Set



3. Map

  • 다양한 자료형의 key를 허용하고, key-value 형태의 자료형을 저장 가능할 수 있는 Collection
  • Map은 Object 대비 비교하면 다양한 key의 사용을 허용하고, 값의 추가/삭제 시 메서드를 통해 수행이 필요하다
  • 생성자 : new Map()
  • 갯수 확인 : Map.size
  • 요소 추가 : Map.set(key, value)
  • 요소 접근 : Map.get(key, value)
  • 요소 삭제 : Map.delete(key)
  • 전체 삭제 : Map.claer()
  • 요소 존재 여부 확인 : Map.has(key)
  • 그 밖의 메서드 : Map.keys(), Map.values(), Map.entires()


요소 추가/삭제

let map = new Map()

map.set("name", "John")
console.log(map)
//Map(1) { 'name' => 'John' }

map.set("123", "456")
console.log(map)
//Map(2) { 'name' => 'John', '123' => '456' }

map.set(true, "bool_type")
console.log(map)
//Map(3) { 'name' => 'John', '123' => '456', true => 'bool_type' }

console.log(map.get("123")) //456
console.log(map.get("name")) //John
console.log(map.get(true)) //bool_type

console.log(map.size) //3

map.delete("123")
console.log(map)
//Map(2) { 'name' => 'John', true => 'bool_type' }

map.clear()
console.log(map)
//Map(0) {}

map.set(123, 789).set(false, "bool_type").set("fruit", "banana")
console.log(map)
//Map(3) { 123 => 789, false => 'bool_type', 'fruit' => 'banana' }
  • 요소 추가 : Map.set(key, value)
  • 요소 접근 : Map.get(key, value)
  • 전체 삭제 : Map.claer()
  • 다양한 자료형을 key로 사용 가능하며, map.set 호출 시 map 이 반환되므로 체이닝(chaining) 가능


Map 반복문

let recipe_juice = new Map([
  ["strawberry", 50],
  ["banana", 100],
  ["ice", 150],
]);

for (let item of recipe_juice.keys()) {
  console.log(item);
  //   strawberry;
  //   banana;
  //   ice;
}

for (let amount of recipe_juice.values()) {
  console.log(amount);
  //   50;
  //   100;
  //   150;
}

for (let entity of recipe_juice) {
  console.log(entity);
//   ["strawberry", 50][("banana", 100)][("ice", 150)];
}

  • Collection 객체인 Map이 가지고 있는 iterator 속성을 이용하여 for...of 구문을 통해 반복문 수행 가능


Map <> Object 변환

let recipe_juice = new Map([
  ["strawberry", 50],
  ["banana", 100],
  ["ice", 150],
]);

console.log(recipe_juice)
//Map(3) { 'strawberry' => 50, 'banana' => 100, 'ice' => 150 }

let recipe_juice_obj = Object.fromEntries(recipe_juice)
console.log(recipe_juice_obj)
//{ strawberry: 50, banana: 100, ice: 150 }

let recipe_juice_kv = Object.entries(recipe_juice_obj)
console.log(recipe_juice_kv)
// [ [ 'strawberry', 50 ], [ 'banana', 100 ], [ 'ice', 150 ] ]

let recipe_juice_map = new Map(recipe_juice_kv)
console.log(recipe_juice_map)
//Map(3) { 'strawberry' => 50, 'banana' => 100, 'ice' => 150 }
  • Object.entries(Object), Object.fromEntries(Map)을 통해 Map과 Object 간 변환이 가능



Set

  • value 만을 저장하며 중복을 허용하지 않는 Collection
  • 생성자 : new Set()
  • 갯수 확인 : Set.size
  • 요소 추가 : Set.add(value)
  • 요소 삭제 : Set.delete(value)
  • 전체 삭제 : Set.claer()
  • 요소 존재 여부 확인 : Set.has(key)
  • 그 밖의 메서드 : Set.keys(), Set.values(), Set.entries()


요소 추가/삭제

let set = new Set()
let num = new Set([1, 2, 3, 4, 5])
let str = new Set("Hello!")

console.log(set) //Set(0) {}
console.log(num) //Set(5) { 1, 2, 3, 4, 5 }
console.log(str) //Set(5) { 'H', 'e', 'l', 'o', '!' }

set.add(1).add(2).add(10).add(10)
console.log(set) //Set(3) { 1, 2, 10 }

console.log(set.has(10)) //true
console.log(set.has(100)) //false

console.log(set.delete(100)) //false
console.log(set.delete(10)) //true
console.log(set) //Set(2) { 1, 2 }
  • 요소 추가 : Set.add(value)
  • 요소 존재 여부 확인 : Set.has(key)
  • 요소 삭제 : Set.delete(value)
  • 다양한 자료형을 value로 사용 가능하며, set.add 호출 시 set이 반환되므로 체이닝(chaining) 가능


Set 반복문

let str = new Set("Hello!");

console.log(str);
//Set(5) { 'H', 'e', 'l', 'o', '!' }

for (let item of str) {
  console.log(item);
  // H
  // e
  // l
  // o
  // !
}

// key 와 value 가 없기 때문에 안쓴것과 동일하다
for (let item of str.keys()) {
  console.log(item);
  // H
  // e
  // l
  // o
  // !
}

for (let item of str.values()) {
  console.log(item);
  // H
  // e
  // l
  // o
  // !
}

for (let item of str.entries()) {
  console.log(item);
  //   [ 'H', 'H' ]
  // [ 'e', 'e' ]
  // [ 'l', 'l' ]
  // [ 'o', 'o' ]
  // [ '!', '!' ]
  // Map 과의 포맷을 지키기 위해 해당 형태로 반환한다.
}

  • Collection 객체인 Set 이 가지고 있는 iterator 속성을 이용하여 for...of 구문을 통해 반복문 수행 가능



5. Math

  • 표준 Built-in 객체로서 수학적인 연산을 취한 속성값과 메서드를 제공하는 객체
  • Math는 생서자 함수가 아니며, 모든 속성과 메서드는 정적이기에 Math.function()으로 언제든 호출 가능
  • 오일러 상수(e) : Math.E
  • PI : Math.PI
  • 절대값: Math.abs(x)
  • 최대값 : Math.max(...x)
  • 최소값 : Math.min(...x)
  • 랜덤 난수 값 : Math.random()
  • 제곱과 제곱근 : Math.pow(x,y), Math.sqrt(x)
  • 소수점 처리 : Math.round(x), Math.ceil(x), Math.floor(x)


최대/최소/절대값

console.log(Math.max(1, -1, 6, 8, 10, 12)); //12
console.log(Math.min(1, -1, 6, 8, 10, 12)); //-1

let nums = [1, -1, 6, 8, 10, 12]
console.log(Math.max.apply(null, nums)) //12
console.log(Math.min.apply(null, nums)) //-1

console.log(Math.max(...nums)) //12
console.log(Math.min(...nums)) //-2

console.log(Math.abs(-2)) //2
console.log(Math.abs(2)) //2
console.log(Math.abs(-Infinity)) //Infinity
  • 배열을 인수로 받아 최대/최소를 산출하려면 apply 함수 혹은 스프레드 문법 사용 필요


속성 및 랜덤

// property
console.log(Math.E) //2.718281828459045
console.log(Math.PI) //3.141592653589793

// random 값의 범위를 다양하게 표현 가능
console.log(())  //0.6255519540470105
console.log(Number.parseInt(Math.random() * 10))  //6
console.log(Number.parseInt(Math.random() * 100))  //62


  • 0과 1 사이의 난수 랜덤 값 : Math.random()


제곱/제곱근/소수점 처리

// 제곱
console.log(Math.pow(2,3)) //8
console.log(2 ** 3) //8

// 제곱근
console.log(Math.sqrt(4)) //2
console.log(Math.sqrt(2)) //1.4142135623730951

// 반올림
console.log(Math.round(3.5)) //4
console.log(Math.round(-2.7)) //-3
console.log(Math.round(-2.3)) //-2

// 올림
console.log(Math.ceil(3.5)) //4
console.log(Math.ceil(-2.7)) //-2
console.log(Math.ceil(-2.3)) //-2

// 내림
console.log(Math.floor(3.5)) //3
console.log(Math.floor(-2.7)) //-3
console.log(Math.floor(-2.3)) //-3
  • 제곱 : Math.pow(x,y)
  • 제곱근 : Math.sqrt(x)
  • 소수점 이하 반올림 정수 : Math.round(x)
  • 소수점 이하 올림 : Math.ceil(x)
  • 소수점 이하 내림 : Math.floor(x)



6. Date

  • 표준 Built-in 객체로서 날짜와 시간을 위한 속성값과 메서드를 제공하는 객체
  • Date 객체는 1970년 1월 1일 UTC(협정 세계시) 자정과의 시간 차이를 밀리초로 나타내는 정수 값으로 표현
  • Date 객체 생성자 : new Date()
  • 현재 시간 기준 문자열 : Date()
  • 날짜 정보 얻기 (년/월/일) : Date.getFullYear(), Date.getMonth(), Date.getDate()
  • 날짜 정보 얻기 (시/분/초/ms) : Date.getHours(), Date.getMinutes(), Date.getSeconds()
  • 날짜 정보 설정 (년/월/일) : Date.setFullYear(), Date.setMonth(), Date.setDate()
  • 날짜 정보 설정 (시/분/초/ms) : Date.setHours(), Date.setMinutes(), Date.setSeconds()
  • 그 외 날짜 정보 얻기 : Date.getDay(), Date.getTime(), Date.getTimezoneOffset()
  • 그 외 날짜 정보 설정 : Date.parse(string)


Date 생성자 종류

let date_now = new Date()
let date_str = Date()

console.log(date_now) //2021-09-28T03:11:16.461Z
console.log(date_str) //Tue Sep 28 2021 12:11:16 GMT+0900 (Korean Standard Time)

console.log(typeof date_now) //object
console.log(typeof date_str) //string

let date_ms_1 = new Date(0)
console.log(date_ms_1) //1970-01-01T00:00:00.000Z

date_ms_1 = new Date(1000 * 3600 * 24)
console.log(date_ms_1) //1970-01-02T00:00:00.000Z 하루 지난 값

let date_string = new Date("2021-09-28")
console.log(date_string) //2021-09-28T00:00:00.000Z

// month 는 0~11월
let date_param_1 = new Date(2021, 0, 1)
console.log(date_param_1) //2020-12-31T15:00:00.000Z
// 끝이 Z는 UTC 기준이다. 우리나라는 -9hour 해야한다.

let date_param_2 = new Date(Date.UTC(2021, 0, 1)) // UTC 고정하는 법
console.log(date_param_2) //2021-01-01T00:00:00.000Z

  • new Date(), new Date(miniseconds), new Date(datestring)
  • new Date(year, month, date, hours, minutes, seconds, ms)


날짜 정보 얻기

// 🤔
let date = new Date()
console.log(date) //2021-09-28T03:17:56.836Z

console.log(date.getFullYear()) //2021
console.log(date.getMonth()) //8 > 9월
// 일요일이 0 ~ 토요일이 6
console.log(date.getDay()) //2 > 화요일

console.log(date.getHours()) //12
// UTC 고정된 값 (우리나라로부터 - 15)
console.log(date.getUTCHours()) //9

// ms 단위
console.log(date.getTime()) //1632799299226
console.log(new Date(date.getTime())) //2021-09-28T03:21:39.226Z

//UTC 로부터 얼마나 차이나는지 분 기준으로
console.log(date.getTimezoneOffset()) // -540 => -9시간
  • 날짜 정보 얻기 (년/월/일) : Date.getFullYear(), Date.getMonth(), Date.getDate()
  • 날짜 정보 얻기 (시/분/초/ms) : Date.getHours(), Date.getMinutes(), Date.getSeconds()
  • 주어진 일시 - 1970/1/1 차분(ms) : Date.getTime(), 현지시간-표준 시간 차분(min) : Date.getTimezoneOffset()


날짜 정보 설정

let date = new Date()
console.log(date) //2021-09-28T03:17:56.836Z

let ms_year = date.setFullYear(2020, 3, 15)

console.log(date) //2020-04-15T03:25:32.281Z
console.log(ms_year) //1586921132281 > ms
console.log(new Date(ms_year)) //2020-04-15T03:26:13.683Z > date 와 같은 값

date.setDate(1)
console.log(date) //2020-04-01T03:26:55.477Z

// 0으로 지정하면 이전달
date.setDate(0)
console.log(date) //2020-03-31T03:27:18.635Z

date.setHours(date.getHours() + 2) // 현재 시간에서 2시간 더하기
console.log(date) //2020-03-31T05:27:54.202Z
  • 날짜 정보 설정 (년/월/일) : Date.setFullYear(), Date.setMonth(), Date.setDate()
  • 날짜 정보 설정 (시/분/초/ms) : Date.setHours(), Date.setMinutes(), Date.setSeconds()


parse

let ms_parse = Date.parse("2020-03-31T00:00:00.000") // 로컬기준

console.log(ms_parse) //1585580400000
console.log(new Date(ms_parse)) //2020-03-30T15:00:00.000Z > (UTC0는 +9시간 해야 된다.)

// 애초에 UTC0 로 설정하려면?
ms_parse = Date.parse("2020-03-31T00:00:00.000Z")
console.log(ms_parse) //1585612800000
console.log(new Date(ms_parse)) //2020-03-31T00:00:00.000Z
  • parse 는 ms 반환
  • 날짜 정보 설정
  • 문자열 기반 날짜 정보 설정 : Date.parse(YYYY-MM-DDTHH:mm:ss.sssZ)
  • YYYY-MM-DD : 날짜 (연-월-일)
  • T : 구분 기호
  • HH:mm:ss.sss : 시, 분, 초, 밀리초
  • Z (option) : 미 설정할 경우 현재 로컬 기준 UTC로, 설정할 경우 UTC+0 기준으로 시간 설정


benchmark

function dateSub(old_date, new_date) {
  return new_date - old_date;
}
function getTimeSub(old_date, new_date) {
  return new_date.getTime() - old_date.getTime();
}

function benchmark(cb) {
  let date1 = new Date("2020-01-01");
  let date2 = new Date();

  let start = Date.now();
  for (let i = 0; i < 100000; i++) {
    cb(date1, date2);
  }
  return Date.now() - start;
}

console.log("dateSub: " + benchmark(dateSub) + "ms") //dateSub: 16ms
console.log("getTimeSub: " + benchmark(getTimeSub) + "ms") //getTimeSub: 5ms
  • 성능 측정
  • 벤치마크 측정 대상 함수 전호루 시간을 비교하여 알고리즘 성능 측정
  • 알고리즘 성능 평가 시 사용



7. N차원 Array

  • 배열(Array) 안에 N개 만큼의 배열이 존재하는 객체
  • 2,3차원 지도 정보, RGB를 저장하는 2차원 사진 파일 등을 표현할 때 활용 가능
  • Array[N][M]


2차원 배열

let arr = [
    [1,2,3],
    [4,5,6],
    [7,8,9]
]

console.log(arr) //[ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]
console.log(arr[0]) //[ 1, 2, 3 ]
console.log(arr[1][0]) //4
console.log(arr.length) // 3

let arr2 = arr.pop()
console.log(arr.length) //2
console.log(arr) //[ [ 1, 2, 3 ], [ 4, 5, 6 ] ]
console.log(arr2) //[ 7, 8, 9 ]

let arr3 = arr.push([10, 11, 12])
console.log(arr.length) //3
console.log(arr) //[ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 10, 11, 12 ] ]
console.log(arr3) // push 된 배열의 최종 길이
let arr = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
];

for (let i = 0; i < arr.length; i++) {
  for (let j = 0; j < arr[i].length; j++) {
    console.log(arr[i][j]);
    // 1 2 3 4 5 6 7 8 9
  }
}

// 이런식으로 data 저장하는 방법 잘 안 쓰인다.

let fruits = [
  ["apple", 50],
  ["banana", 100],
  ["melon", 3],
];

for (i = 0; i < fruits.length; i++) {
  console.log("name : " + fruits[i][0] + " amount : " + fruits[i][1]);
  //   name : apple amount : 50
  // name : banana amount : 100
  // name : melon amount : 3
}

  • array[N][M]으로 접근하며, 배열(Array) 전체를 push(), pop() 가능
  • 이중 for loop 를 사용한 2차원 배열 접근



나의 회고 🤫

우와 드디어 Js 대장정 종료다..!
어떤 언어든 가장 그 언어의 자료구조를 활용할 수 있는 컬렉션…너무 어렵다…ㅠㅠ
정말 7,8,9 페이지는 틈날때마다 들려서 살펴봐야겠다.
전체적인 js 문법을 돌아볼수 있었지만 spread 연산자와 함수 중 원시 함수의 불변성을 보장하는 함수를 따로 정리해서 공부해두면 좋을 것 같다.