🎉 berenickt 블로그에 온 걸 환영합니다. 🎉
Lang
JavaScript
06-기본 자료구조-Array, Map, Set

1. 자료구조란?

밀접하게 관련된 상태나 행동을 묶어서 객체로 표현합니다. 이떄 (이름, 나이, 성별) 같은 상태와 (말한다, 먹는다) 같은 행동을 묶어놓은 사람이라는 템플릿을 만들 수 있었습니다. 클래스나 생성자 함수를 이용해서 템플릿을 잘 만들어두면 철수, 영희같은 실질 데이터가 들어있는 사람을 만들 수 있었습니다. 이렇게 클래스를 통해 만들어진 것을 인스턴스라고 했습니다. 이렇게 밀접한 정보와 행동들을 묶어서 객체로 만들 수 있습니다.

이렇게 여러 개의 객체를 특정한 자료구조에 담아둘 수 있습니다. 예를 들면, 어떤 사람들이 집합체를 만들 수 있겠죠. 그래서 사람을 모아놓은 집합체를 어떻게 나타낼 수 있을지 또는 줄을 서서 기다리는 사람도 나타낼 수 있어요. 서버에서 클라이언트에게 들어온 요청을 큐 형태로 보관해서 먼저 들어온 요청을 먼저 처리할 수 있도록 만들 수 있겠죠.


2. Array(배열)

배열의 특징

  • index를 기반으로 필요한 데이터를 저장
  • 순서가 중요
  • 중복 가능
  • cf. MDN Array

2.1 배열 생성 방법

1
let array = new Array(3) // 3개의 사이즈를 가진 빈 배열 생성
2
console.log(array) // [ <3 empty items> ]
3
4
array = new Array(1, 2, 3) // 3개의 아이템을 가진 배열 생성
5
console.log(array) // [ 1, 2, 3 ]
6
7
array = Array.of(1, 2, 3, 4, 5) // of 함수로 배열 생성
8
console.log(array) // [ 1, 2, 3, 4, 5 ]
9
10
const anotherArray = [1, 2, 3, 4] // 리터럴을 이용해 배열 생성
11
console.log(anotherArray) // [ 1, 2, 3, 4 ]
12
13
array = Array.from(anotherArray) // 기존의 배열에서 새로운 배열을 생성
14
console.log(array) // [ 1, 2, 3, 4 ]
15
16
// 일반적으로 배열은 동일한 메모리 크기를 가지며, 연속적으로 이어져 있어함
17
// 하지만 자바스크립트에서의 배열은 연속적으로 이어져 있지 않고, 오브젝트와 유사함!
18
// 자바스크립트의 배열은 일반적인 배열의 동작을 흉내낸 특수한 객체다!
19
// 이걸 보완하기 위해서 타입이 정해져 있는 타입 배열이 있음 (Typed Collections)
20
array = Array.from({
21
// 오브젝트로 배열 생성
22
0: '안',
23
1: '녕',
24
length: 2,
25
})
26
console.log(array) // [ '안', '녕' ]

2.2 하면 안되는 것

1
const fruits = ['🍌', '🍎', '🍇', '🍑']
2
3
// 배열 아이템을 참조하는 방법
4
console.log(fruits[0])
5
console.log(fruits[1])
6
console.log(fruits[2])
7
console.log(fruits[3])
8
console.log(fruits.length) // 4
9
10
// for문으로 배열 아이템 참조하는 방법
11
for (let i = 0; i < fruits.length; i++) {
12
console.log(fruits[i]) // 🍌, 🍎, 🍇, 🍑
13
}
14
15
// const fruits = ['🍌', '🍎', '🍇', '🍑'];
16
// 추가, 삭제 - 좋지 않은 방식 💩, 참고용
17
// 인덱스로 바로 접근해서 추가하는 것은 좋은 방식이 아님
18
// 추가하려면 아래 방식을 사용
19
// fruits[fruits.length] = '🍓';
20
fruits[6] = '🍓'
21
console.log(fruits) // [ '🍌', '🍎', '🍇', '🍑', <2 empty items>, '🍓' ]
22
23
// 동일한 원리로 인덱스로 바로 접근해서 삭제하는 것은 좋은 방식이 아님
24
delete fruits[1]
25
console.log(fruits) // [ '🍌', <1 empty item>, '🍇', '🍑', <2 empty items>, '🍓' ]

2.3 사용할 수 있는 함수⭐

  1. isArray : 특정한 오브젝트가 배열인지 체크, MDN Array.isArray()
  2. indexOf : 특정한 아이템의 위치를 찾을때, MDN Array.prototype.indexOf()
  3. includes : 배열안에 특정한 아이템이 있는지 체크, MDN Array.prototype.includes()
  4. push : 추가 - 제일 뒤, MDN Array.prototype.push()
  5. unshift: 추가 - 제일 앞, MDN Array.prototype.unshift()
  6. pop: 제거 - 제일 뒤, MDN Array.prototype.pop()
  7. shift : 제거 - 제일 앞, MDN Array.prototype.shift()
  8. splice(붙이다) : 중간에 추가 또는 삭제, MDN Array.prototype.splice()
  9. slice : 잘라진 새로운 배열을 만듬, MDN Array.prototype.slice()
  10. concat : 여러개의 배열을 붙여줌, MDN Array.prototype.concat()
  11. reverse : 순서를 거꾸로, MDN Array.prototype.reverse()
  12. flat : 중첩 배열을 하나의 배열로 쫙 펴기, MDN Array.prototype.flat()
  13. fill : 특정한 값으로 배열을 채우기, MDN Array.prototype.fill()
  14. join : 배열을 문자열로 합하기, MDN Array.prototype.join()
1
// 배열의 함수들
2
// 배열 자체를 변경하는지, 새로운 배열을 반환하는지
3
const fruits = ['🍌', '🍎', '🍋']
4
5
// 1. 특정한 오브젝트가 배열인지 체크
6
console.log(Array.isArray(fruits)) // true
7
console.log(Array.isArray({})) // false
8
9
// 2. 특정한 아이템의 위치를 찾을때
10
console.log(fruits.indexOf('🍎')) // 1
11
12
// 3. 배열안에 특정한 아이팀이 있는지 체크
13
console.log(fruits.includes('🍎')) // true
14
15
// 4. 추가 - 제일 뒤
16
let length = fruits.push('🍑') // 배열 자체를 수정(업데이트)
17
console.log(fruits) // [ '🍌', '🍎', '🍋', '🍑' ]
18
console.log(length) // 4
19
20
// 5. 추가 - 제일 앞
21
length = fruits.unshift('🍓') // 배열 자체를 수정(업데이트)
22
console.log(fruits) // [ '🍓', '🍌', '🍎', '🍋', '🍑' ]
23
console.log(length) // 5
24
25
// 6. 제거 - 제일 뒤
26
let lastItem = fruits.pop() // 배열 자체를 수정(업데이트)
27
console.log(fruits) // [ '🍓', '🍌', '🍎', '🍋' ]
28
console.log(lastItem) // 🍑
29
30
// 7. 제거 - 제일 앞
31
lastItem = fruits.shift() // 배열 자체를 수정(업데이트)
32
console.log(fruits) // [ '🍌', '🍎', '🍋' ]
33
console.log(lastItem) // 🍓
34
35
// 8. 중간에 추가 또는 삭제, splice = 붙이다
36
const deleted = fruits.splice(1, 1) // 1번 인덱스에 1개를 삭제
37
console.log(fruits) // 배열 자체를 수정(업데이트), [ '🍌', '🍋' ]
38
console.log(deleted) // [ '🍎' ]
39
fruits.splice(1, 1, '🍎', '🍓') // 1번 인덱스에 1개를 삭제하고, '🍎', '🍓'를 추가
40
console.log(fruits) // 배열 자체를 수정(업데이트), [ '🍌', '🍎', '🍓' ]
41
42
// 9. 잘라진 새로운 배열을 만듬, slice = 자르다
43
let newArr = fruits.slice(0, 2) // 0번에서 2번 인덱스 이전까지 잘라서 새 배열 생성
44
console.log(newArr) // [ '🍌', '🍎' ]
45
console.log(fruits) // [ '🍌', '🍎', '🍓' ]
46
newArr = fruits.slice(-1) // 뒤에서 부터 자르기
47
console.log(newArr) // [ '🍓' ]
48
49
// 10. 여러개의 배열을 붙여줌, concatenate = 연결하다
50
const arr1 = [1, 2, 3]
51
const arr2 = [4, 5, 6]
52
const arr3 = arr1.concat(arr2)
53
console.log(arr1)
54
console.log(arr2)
55
console.log(arr3) // [ 1, 2, 3, 4, 5, 6 ]
56
57
// 11. 순서를 거꾸로
58
const arr4 = arr3.reverse()
59
console.log(arr4) // [ 6, 5, 4, 3, 2, 1 ]
60
console.clear()
61
62
// 12. 1단계까지만 중첩 배열을 하나의 배열로 쫙 펴기, flat = 평평한
63
let arr = [
64
[1, 2, 3],
65
[4, [5, 6, [3, 4]]],
66
]
67
console.log(arr) // [ [ 1, 2, 3 ], [ 4, [ 5, 6, [Array] ] ] ]
68
console.log(arr.flat(3)) // [ 1, 2, 3, 4, 5, 6, 3, 4 ]
69
arr = arr.flat(3)
70
71
// 13. 특정한 값으로 배열을 채우기, fill = 채우다
72
arr.fill(0) // 배열 자체를 모두 0으로 수정
73
console.log(arr) // [0, 0, 0, 0, 0, 0, 0, 0]
74
75
arr.fill('s', 1, 3) // 1번 인덱스부터 3번 인덱스 이전까지 s로 채우기
76
console.log(arr) // [0, 's', 's', 0, 0, 0, 0, 0]
77
78
arr.fill('a', 1) // 1번 인덱스부터 끝까지 a로 채우기
79
console.log(arr) // [0, 'a', 'a', 'a', 'a', 'a', 'a', 'a']
80
81
// 14. 배열을 문자열로 합하기, join = 합치다
82
let text = arr.join()
83
console.log(text) // 0,a,a,a,a,a,a,a
84
text = arr.join(' | ')
85
console.log(text) // 0 | a | a | a | a | a | a | a

2.4 얕은 복사(Shallow Copy)

1
// 얕은 복사(Shallow Copy) - 객체는 메모리 주소 전달
2
// 자바스크립트에서 복사할때는 항상 얕은 복사가 이루어짐!
3
// Array.from, concat, slice, spread(...), Object.assign
4
// 오브젝트(객체) 생성
5
const pizza = { name: '🍕', price: 2, owner: { name: 'Ellie' } }
6
const ramen = { name: '🍜', price: 3 }
7
const sushi = { name: '🍣', price: 1 }
8
9
const store1 = [pizza, ramen] // 배열 생성
10
const store2 = Array.from(store1) // 새로운 배열 생성
11
console.log('store1', store1)
12
// store1[({ name: '🍕', price: 2, owner: { name: 'Ellie' } }, { name: '🍜', price: 3 })]
13
console.log('store2', store2)
14
// store2[({ name: '🍕', price: 2, owner: { name: 'Ellie' } }, { name: '🍜', price: 3 })]
15
16
store2.push(sushi)
17
console.log('store1', store1)
18
// store1 [
19
// { name: '🍕', price: 2, owner: { name: 'Ellie' } },
20
// { name: '🍜', price: 3 }
21
// ]
22
console.log('store2', store2)
23
// store2 [
24
// { name: '🍕', price: 2, owner: { name: 'Ellie' } },
25
// { name: '🍜', price: 3 },
26
// { name: '🍣', price: 1 }
27
// ]
28
29
// 피자의 가격을 4로 인상하면서 배열을 수정하지 않아도, 피자의 가격이 변경됨
30
// 얕은 복사(Shallow Copy) - 객체는 메모리 주소 전달
31
pizza.price = 4
32
console.log('store1', store1)
33
// store1 [
34
// { name: '🍕', price: 4, owner: { name: 'Ellie' } },
35
// { name: '🍜', price: 3 }
36
// ]
37
console.log('store2', store2)
38
// store2 [
39
// { name: '🍕', price: 4, owner: { name: 'Ellie' } },
40
// { name: '🍜', price: 3 },
41
// { name: '🍣', price: 1 }
42
// ]

3. Set

Set는 데이터의 집합체라고 볼 수 있습니다. 순서도 없고, 중복도 불가능합니다.

  1. size : 사이즈 확인
  2. has() : 존재하는지 확인
  3. forEach() : 순회
  4. add() : 추가
  5. delete() : 삭제
  6. clear() : 전부 삭제
1
// Set : 데이터의 집합체, 인덱스 X, 중복X
2
const set = new Set([1, 2, 3])
3
console.log(set) // Set(3) { 1, 2, 3 }
4
5
// 1. 사이즈 확인
6
console.log(set.size) // 3
7
8
// 2. 존재하는지 확인
9
console.log(set.has(2)) // true
10
console.log(set.has(6)) // false
11
12
// 3. 순회
13
set.forEach(item => console.log(item)) // 1, 2, 3
14
for (const value of set.values()) {
15
console.log(value) // 1, 2, 3
16
}
17
18
// 4. 추가
19
set.add(6)
20
console.log(set) // Set(4) { 1, 2, 3, 6 }
21
set.add(6)
22
console.log(set) // Set(4) { 1, 2, 3, 6 }, 중복 X
23
24
// 5. 삭제
25
set.delete(6)
26
console.log(set) // Set(3) { 1, 2, 3 }
27
28
// 6. 전부 삭제
29
set.clear()
30
console.log(set) // Set(0) {}

4. Map

Map은 [키, 값]형태로 이루어진 자료구조라고 생각하면 됩니다. Map은 순서가 중요하지 않습니다. 다만, Key는 유일해야 합니다. 그래서 Key만 다르다면 중복이 가능합니다.

  1. size : 사이즈 확인
  2. has() : 존재하는지 확인
  3. forEach() : 순회
  4. get() : 찾기
  5. set() : 추가
  6. delete() : 삭제
  7. clear() : 전부삭제
1
const map = new Map([
2
['key1', '🍎'],
3
['key2', '🍌'],
4
])
5
console.log(map) // Map(2) { 'key1' => '🍎', 'key2' => '🍌' }
6
7
// 1. 사이즈 확인
8
console.log(map.size) // 2
9
10
// 2. 존재하는지 확인
11
console.log(map.has('key1')) // true
12
console.log(map.has('key6')) // false
13
14
// 3. 순회
15
map.forEach((value, key) => console.log(key, value)) // key1 🍎, key2 🍌
16
console.log(map.keys()) // [Map Iterator] { 'key1', 'key2' }
17
console.log(map.values()) // [Map Iterator] { '🍎', '🍌' }
18
console.log(map.entries()) // [Map Entries] { [ 'key1', '🍎' ], [ 'key2', '🍌' ] }
19
20
// 4. 찾기
21
console.log(map.get('key1')) // 🍎
22
console.log(map.get('key2')) // 🍌
23
console.log(map.get('key4')) // undefined
24
25
// 5. 추가
26
map.set('key3', '🥝')
27
console.log(map) // Map(3) { 'key1' => '🍎', 'key2' => '🍌', 'key3' => '🥝' }
28
29
// 6. 삭제
30
map.delete('key3')
31
console.log(map) // Map(2) { 'key1' => '🍎', 'key2' => '🍌' }
32
33
// 7. 전부삭제
34
map.clear()
35
console.log(map) // Map(0) {}

Object도 [키, 값]으로 이루어져 있습니다. 그래서 Object를 Map처럼 사용할 수 있고, Map을 Object처럼 사용할 수 있습니다.

1
// 오브젝트와의 큰 차이점?? 사용할 수 있는 함수가 다름, Map키에 직접 접근 불가(get사용해야 함)
2
const key = { name: 'milk', price: 10 }
3
const milk = { name: 'milk', price: 10, description: '맛있는우유' }
4
5
// 1) 오브젝트를 사용
6
const obj = {
7
[key]: milk,
8
}
9
console.log(obj)
10
// Map(0) {} {
11
// '[object Object]': { name: 'milk', price: 10, description: '맛있는우유' }
12
// }
13
14
// 2) Map을 사용
15
const map2 = new Map([[key, milk]])
16
console.log(map2)
17
// Map(1) {
18
// { name: 'milk', price: 10 } => { name: 'milk', price: 10, description: '맛있는우유' }
19
// }
20
21
console.log(obj[key]) // { name: 'milk', price: 10, description: '맛있는우유' }
22
console.log(map2[key]) // undefined, 키에 직접 접근 불가능, get 사용해야 함
23
console.log(map2.get(key)) // { name: 'milk', price: 10, description: '맛있는우유' }