
헷갈리는 것들만 따로 정리할 예정.
deep dive 책을 함께 공부함.
9. 배열 (Array)
요즘에는 특정한 데이터 타입만 넣을 수 있는 Array를 만들 수 있음.
이렇게 데이터 타입이 지정된 배열을 쓰면 그 외에 데이터 타입을 넣게 되면 에러가 발생.
ex : Int8Array, Unit8Array, Float32Array, Float64Array 등...
9-1) 배열 생성 방법
[1] 생성자 함수
let array = new Array(2);
// 사이즈를 지정 가능
// 2개의 비어있는 아이템이 생김
console.log(array);
// [ <2 empty items> ]
array = new Array(1, 2, 3);
// 내가 만들고 싶은 아이템을 전달해도 됨
console.log(array);
// [ 1, 2, 3 ]
[2] static 함수 Array.of()
array = Array.of(1, 2);
// 요소들의 집합으로부터 새로운 배열을 반환
console.log(array);
// [ 1, 2 ]
[3] 배열 리터럴
const anotherArray = [1, 2, 3, 4];
console.log(anotherArray);
// [ 1, 2, 3, 4 ]
[4] static 함수 Array.from()
array = Array.from(anotherArray);
// anotherArray 변수에 담긴 배열을 복사해서 새로운 배열로 반환.
console.log(array);
// [ 1, 2, 3, 4 ]
array = Array.from("TEXT");
// from은 새로운 array를 만드는데 iterable object로부터 iterable을 전달 받음.
// iterable은 순회가 가능한 모든 것을 전달할 수 있음.
// 문자열도 순회가 가능하므로 iterable로 문자열을 전달할 수도 있음.
console.log(array);
// [ 'T', 'E', 'X', 'T' ]
일반적으로 array는 동일한 메모리 크기를 가지며, 연속적으로 이어져 있어야 함.
but, 자바스크립트의 array는 연속적으로 이어져 있지 않고 object와 유사.
자바스크립트에서의 array는 일반적인 array의 동작을 흉내넨 특수한 object.
=> 이걸 보완하기 위해서 type이 정해져 있는 type array가 있음 (Typed Collections)
❗ object로부터 배열 만들기
array = Array.from({
0 : "안",
1 : "녕",
length : 2,
});
// object로부터 배열을 만들기 위해서는 object에 두 가지 종류의 키를 넣어주면 됨.
// 첫 번 째는 원하는 아이템 값을 넣어주기 위한 index key.
// 두 번 째는 몇 개의 아이템을 넣을 것인지 표기할 length key.
console.log(array);
// [ "안", "녕" ]
9-2) 배열 접근 및 아이템 추가, 삭제 방법
[1] 배열에 접근
const fruits = ["🍌", "🍎", "🍇", "🍑"];
console.log(fruits[0]); // 🍌
console.log(fruits[1]); // 🍎
console.log(fruits[2]); // 🍇
console.log(fruits[3]); // 🍑
// index로 배열에 접근하여 아이템 값을 얻을 수 있음.
console.log(fruits.length);
// instance property(속성) length를 사용하여 배열의 길이를 값으로 얻을 수 있음.
[2] 반복문을 통한 배열 순회
for(let i = 0; i < fruits.length; i++){
console.log(fruits[i]);
}
// 🍌
// 🍎
// 🍇
// 🍑
// 배열에 여러 번 접근할 필요 없이 for문 한 번으로 배열의 아이템 값을 차례대로 얻어낼 수 있음.
[3] 아이템 추가, 삭제
3-1) 좋지 못한 방식
index로 배열의 아이템에 바로 접근하는 것은 좋지 못한 방식임.
fruits[3] = "🍓";
console.log(fruits);
// ["🍌", "🍎", "🍇", "🍑", "🍓"]
fruits[fruits.length] = "🍓";
// index.length로 추가하게 되면 맨 마지막에 넣을 수 있지만 역시 좋은 방식이 아님
console.log(fruits);
// [ '🍌', '🍎', '🍇', '🍓', '🍓' ]
delete fruits[1];
console.log(fruits);
// [ '🍌', <1 empty item>, '🍇', '🍓', '🍓' ]
// delete을 이용해서 index에 접근해 아이템을 삭제할 수 있음
// 이렇게 비우게 되면 그 자리가 empty item으로 비어있게 됨
3-2) 아이템 추가, 삭제를 위한 array method
// array method를 사용할 때 가장 중요하게 봐야 하는 것은
// 배열 자체를 변경하는 것인지, 새로운 배열을 반환하는 것인지임.
const fruits = ["🍌", "🍎", "🍇"];
[1] 기존의 배열이 수정되는 배열 메소드 :
=> push - 새로운 요소를 배열 맨 끝에 추가한 후에 배열의 길이를 return
let length = fruits.push("🍉");
console.log(fruits);
// ["🍌", "🍎", "🍇", "🍉"];
console.log(length);
// 4
=> unshift - 새로운 요소를 배열 맨 앞에 추가한 후에 배열의 길이를 return
let length = fruits.unshift("🍰");
console.log(fruits);
// ["🍰" , "🍌", "🍎", "🍇", "🍉"];
console.log(length);
// 5
=> pop - 배열 맨 뒤 요소를 제거하고 제거된 아이템을 return해줌
let lastItem = fruits.pop();
console.log(fruits);
// [ '🍰', '🍌', '🍎', '🍇' ]
console.log(lastItem);
// 🍉
=> shift - 배열 맨 앞 요소를 제거하고 제거된 아이템을 return해줌
lastItem = fruits.shift();
console.log(fruits);
// [ '🍌', '🍎', '🍇' ]
console.log(lastItem);
// 🍰
=> splice - 중간에 추가 또는 삭제하고 삭제한 아이템을 반환함.
인자 : 시작하는 인덱스, 삭제할 갯수(옵션), 삭제하고 다시 추가할 아이템(옵션).
[1]
const deleted = fruits.splice(1, 1);
console.log(fruits);
// [ '🍌', '🍇' ]
console.log(deleted);
// [ '🍎' ]
[2]
fruits.splice(1, 0, "🍗");
// 아무것도 삭제하지 않고 1번째 자리에 "🍗"를 추가
// 하나가 아니라 여러 개를 추가해줄 수도 있음
console.log(fruits);
// [ '🍌', '🍗', '🍇' ]
=> fill - 특정한 값으로 배열 채우기
인자 : 어떤 것을 채울 건지, 어느 인덱스에서 시작할 것인지(옵션), 어느 인덱스 전에서 끝을 맺을 건지(옵션).
let arr = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
[1]
arr.fill(0);
console.log(arr);
// 0으로 배열을 다 채워줌
// [ 0, 0, 0, 0, 0, 0, 0, 0 ]
[2]
arr.fill("s", 1, 3);
console.log(arr);
// 's'로 1부터 3 전까지 채우기
// [ 0, 's', 's', 0, 0, 0, 0, 0 ]
[3]
arr.fill("n", 1);
console.log(arr);
// 'n'로 1부터 전체 다 채우기
// [ 0, 'n', 'n', 'n', 'n', 'n', 'n', 'n' ]
[2] 새로운 배열을 반환하는 배열 메소드 :
=> slice - 기존에 배열을 유지한 상태로 잘라진 새로운 배열을 return.
인자 : 어느 인덱스에서 시작할 것인지(옵션), 어느 인덱스 전에서 끝을 맺을 건지(옵션).
const fruits = [ '🍌', '🍗', '🍇' ];
[1]
let newArr = fruits.slice(0, 2);
console.log(fruits);
// 기존의 배열은 계속 유지됨.
// [ '🍌', '🍗', '🍇' ]
console.log(newArr);
// 0부터 2 전까지 잘라진 것들을 출력
// [ '🍌', '🍗' ]
[2]
newArr = fruits.slice();
// 아무것도 지정해주지 않으면 전체가 반환됨
console.log(fruits);
// [ '🍌', '🍗', '🍇' ]
console.log(newArr);
// [ '🍌', '🍗', '🍇' ]
[3]
newArr = fruits.slice(-1);
console.log(fruits);
// [ '🍌', '🍗', '🍇' ]
console.log(newArr);
// 맨 뒤에서 한 칸 앞 당긴 것만 잘라내서 반환함
// [ '🍇' ]
=> concat - 여러 개의 배열을 붙여서 새로운 배열로 return함
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = arr1.concat(arr2);
console.log(arr1);
// [1, 2, 3]
console.log(arr2);
// [4, 5, 6]
console.log(arr3);
// [1, 2, 3, 4, 5, 6]
=> reverse - 순서를 거꾸로해서 새로운 배열을 return
const arr4 = arr3.reverse();
console.log(arr4);
// [ 6, 5, 4, 3, 2, 1 ]
=> flat - 중첩 배열을 하나씩 배열로 쫙 펴서 새로운 배열로 return
let flatArray = [
[1, 2, 3],
[4, [5, 6, [3, 4]]],
];
[1]
console.log(flatArray);
console.log(flatArray.flat());
// [ 1, 2, 3, 4, [ 5, 6, [ 3, 4 ] ] ]
[2]
console.log(flatArray.flat(2));
// 1단계까지 중첩된 것을 풀어주기 때문에
// 2단계까지 중첩된 것을 풀어주고 싶다면 ()안에 2를 넣어줘야 함
// [ 1, 2, 3, 4, 5, 6, [ 3, 4 ] ]
[3]
flatArray = flatArray.flat(3);
console.log(flatArray);
// 3단계까지 중첩된 것을 풀어줌.
// [ 1, 2, 3, 4, 5, 6, 3, 4 ]
[3] 배열을 문자열로 합하는 배열 메소드 join
const arr = [ 0, 'n', 'n', 'n', 'n', 'n', 'n', 'n' ];
[1]
let text = arr.join();
console.log(text);
// 0, n, n, n, n, n, n, n
[2]
text = arr.join("|");
console.log(text);
// 콤마 말고 다른 식으로 문자열을 합하고 싶다면
// 0 | n | n | n | n | n | n | n
9-3) Shallow copy(얕은 복사)
Shallow copy - 객체를 복사하게 되면 메모리 주소를 전달하게 되는 것을 의미.자바스크립트에서 복사를 할 때는 항상 Shallow copy가 이뤄짐.=> Array.from, concat, slice, spread(...), Object.assign
function(obj){ 인자로 전달된 object가 있다면 그것을 함수 내부에서 수정하는 것은 위험함. 왜냐하면 기존의 object까지 수정되기 때문.}
const pizza = { name: "🍕", price: 2, owner: { name: "Ellie" } };
const ramen = { name: "🍲", price: 3 };
const sushi = { name: "🍣", price: 1 };
const store1 = [pizza, ramen];
const store2 = Array.from(store1);
console.log("store1", store1);
// store1 [ { name: '🍕', price: 2, owner: { name: 'Ellie' } }, { name: '🍲', price: 3 } ]
console.log("store2", store2);
// store2 [ { name: '🍕', price: 2, owner: { name: 'Ellie' } }, { name: '🍲', price: 3 } ]
store2.push(sushi);
console.log("store1", store1);
// store1 [ { name: '🍕', price: 2, owner: { name: 'Ellie' } }, { name: '🍲', price: 3 } ]
console.log("store2", store2);
// store1 [ { name: '🍕', price: 2, owner: { name: 'Ellie' } }, { name: '🍲', price: 3 }, { name: '🍣', price: 1 } ]
// store1, store2 둘 다 각각 새로 만들어진 배열을 가리킴 ( 서로 다른 레퍼런스 주소)
// 서로 다른 배열이기 때문에 store2에만 sushi를 추가하면 store1에는 영향이 가지 않음
but, 참조하고 있는 object 자체를 수정한다는 것은 얘기가 다름.
pizza.price = 4;
console.log("store1", store1);
// store1 [ { name: '🍕', price: 4, owner: { name: 'Ellie' } }, { name: '🍲', price: 3 } ]
console.log("store2", store2);
// store2 [ { name: '🍕', price: 4, owner: { name: 'Ellie' } }, { name: '🍲', price: 3 }, { name: '🍣', price: 1 } ]
// store1을 만들 때 pizze, ramen 배열의 주소를 복사해오는 것
// 동일한 오브젝트를 가지고 있기 때문에 오브젝트를 수정한다면 store1과 stroe2도 같이 수정됨
9-4) Higher-order function(고차함수)
고차함수에 관하여 알아보기 전에, 일급함수에 관하여 알아보겠음.
일급함수(first-class function) - 함수가 일반 객체처럼 모든 연산이 가능한 것.
- 함수의 매개변수로 전달
- 함수의 반환값
- 할당 명령문
- 동일 비교 대상
그렇다면, Higher-order function(고차함수)은 무엇인가?
고차함수(Higher-order function) - 인자로 함수를 받거나(콜백함수) 함수를 반환하는 함수
- 배열에서도 사용할 수 있는 유용한 고차함수들이 많음.
- 서로 특정한 일을 하는 함수들끼리 엮어놓은 것을 함수형 프로그래밍이라고 함.
- 함수형 프로그래밍을 하기 위해서는 함수 자체를 순수함수(함수 안에서 불변성 유지)로 만드는 것이 중요.
- 순수함수로 만듦으로써 error는 줄이고 가독성은 높일 수 있음.
- 함수형 프로그래밍을 사용 - 데이터 변경 X(불변성 유지), 변수 사용 X, 조건문 X, 반복문 X
이제 배열의 고차함수에는 무엇이 있는지 알아보겠음.
const fruits = ["🍌", "🍓", "🍇", "🍓"];
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
[1] 배열을 빙글 빙글 돌면서 원하는 것(콜백함수)을 할 때
=> forEach 함수
인자 : callback 함수를 받음 => callback 함수의 인자로는 value, index, array를 받음.
fruits.forEach(function (value, index, array) {
console.log("----------------------------");
console.log(value); // value만 사용할 거라면 나머지 인자들은 생략이 가능
console.log(index);
console.log(array);
});
// ----------------------------
// 🍌
// 0
// [ '🍌', '🍓', '🍇', '🍓' ]
// ----------------------------
// 🍓
// 1
// [ '🍌', '🍓', '🍇', '🍓' ]
// ----------------------------
// 🍇
// 2
// [ '🍌', '🍓', '🍇', '🍓' ]
// ----------------------------
// 🍓
// 3
// [ '🍌', '🍓', '🍇', '🍓' ]
// 🍌
// 🍓
// 🍇
// 🍓
fruits.forEach((value) => console.log(value));
// 🍌
// 🍓
// 🍇
// 🍓
[2] 조건에 맞는(콜백함수) 아이템을 찾을 때
=> find : 제일 먼저 조건에 맞는 아이템을 return
const item1 = { name: "🥛", price: 2 };
const item2 = { name: "🍪", price: 3 };
const item3 = { name: "🍙", price: 1 };
const products = [item1, item2, item3, item2];
let result = products.find((value) => value.name === "🍪");
console.log(products);
// [ { name: '🥛', price: 2 }, { name: '🍪', price: 3 }, { name: '🍙', price: 1 }, { name: '🍪', price: 3 } ]
console.log(result);
// { name: '🍪', price: 3 }
=> findIndex : 제일 먼저 조건에 맞는 아이템의 인덱스를 return
result = products.findIndex((value) => value.name === "🍪");
console.log(result);
// 1
=> some : 배열의 아이템들이 부분적으로 조건(콜백함수)에 맞는지 확인
result = products.some((value) => value.name === "🍪");
// 배열 이름이 하나라도 쿠키면 true가 나오도록
console.log(result);
// true
=> every : 배열의 아이템들이 전부 조건(콜백함수)에 맞는지 확인
result = products.every((value) => value.name === "🍪");
// 배열 이름이 전체가 쿠키면 true가 나오도록
console.log(result);
// false
=> filter : 조건에 맞는 모든 아이템들을 새로운 배열로 return.
result = products.filter((item) => item.name === "🍪");
console.log(result);
// [ { name: '🍪', price: 3 },{ name: '🍪', price: 3 } ]
[3] 아이템들을 각각 다른 아이템으로 매핑
=> map : 배열의 아이템들을 다른 아이템으로 매핑하여 새로운 배열을 return.
const nums = [1, 2, 3, 4, 5];
[1]
result = nums.map((item) => item * 2);
console.log(result);
// [ 2, 4, 6, 8, 10 ]
[2]
result = nums.map((item) => {
if (item % 2 === 0) {
return item * 2;
} else {
return item;
}
});
console.log(result);
// [ 1, 4, 3, 8, 5 ]
=> flatMap : map을 하는 대상자가 배열이라면 배열을 flat하게 쫙 펴준 후 새로운 배열을 return.
result = nums.map((item) => [1, 2]);
console.log(result);
// [ [ 1, 2 ], [ 1, 2 ], [ 1, 2 ], [ 1, 2 ], [ 1, 2 ] ]
[1]
result = nums.flatMap((item) => [1, 2]);
console.log(result);
// [ 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 ]
- flatMap 예시
result = ["dream", "coding"].map((text) => text.split(""));
console.log(result);
// map을 사용하면 배열 안에 있는 배열이 펴지지 않으므로
// [ ['d', 'r', 'e', 'a', 'm' ], [ 'c', 'o', 'd', 'i', 'n', 'g' ] ]
// split 메소드를 이용하여 ""를 기준으로 나누고 배열에 담아줌.
[2]
result = ["dream", "coding"].flatMap((text) => text.split(""));
console.log(result);
// 글자들이 한 줄로 분리되어 쫙 펴짐
// [ 'd', 'r', 'e', 'a', 'm', 'c', 'o', 'd', 'i', 'n', 'g' ]
[4] 배열의 아이템들을 정렬
=> sort : 문자열 형태의 오름차순으로 요소를 정렬하고, 기존의 배열을 변경
const texts = ["hi", "abc"];
texts.sort();
console.log(texts);
// [ 'abc', 'hi' ]
const numbers = [0, 5, 4, 2, 1, 10];
numbers.sort();
console.log(numbers);
// [ 0, 1, 10, 2, 4, 5 ] => error : 10은 앞에 1이 있어 1 다음에 나오게 됨
// < 0 : a가 앞으로 정렬, 오름차순
// > 0 : b가 앞으로 정렬, 내림차순
numbers.sort((a, b) => a - b);
// 숫자로 변환하여 정렬하고 싶을 때는 콜백함수를 써야 함
// 앞 - 뒤를 했을 때 마이너스가 되어야만 함 => 10이 1 뒤에 올 수도, 2 앞에 올 수도 없음
console.log(numbers);
// [ 0, 1, 2, 4, 5, 10 ]
[5] 배열의 아이템들을 접어서 값을 하나로 만들어줌.
=> reduce : 배열의 요소들을 접어서 값을 하나로 만들어 return.
인자 : callback 함수를 받음 => callback 함수의 인자로는
previousValue, currentValue, currentIndex, array를 받음.
// reduce의 콜백함수 인자로 계속 더해지는 값을 저장할 sum과 각각의 요소들을 전달받을 value를 넣어줌
result = [1, 2, 3, 4, 5].reduce((sum, value) => (sum += value), 0);
console.log(result);
// 15
// result = [1,2,3,4,5].reduce((sum,value) =>
// {
// sum += value;
// return sum; => return sum += value;와 같은데 바로 return할 경우 중괄호와 return 생략 가능.
// }, 0);
// 0과 같이 처음에 시작할 값을 넣어줄 수 있음
'Javascript' 카테고리의 다른 글
다시 시작하는 자바스크립트 - 배열 퀴즈2(고차함수) (0) | 2023.03.22 |
---|---|
다시 시작하는 자바스크립트 - 배열 퀴즈 (0) | 2023.03.22 |
다시 시작하는 자바스크립트 - 내장객체 퀴즈 (0) | 2023.03.19 |
(심층)자바스크립트다시 시작하는 자바스크립트 - 형 변환, 선언 (0) | 2023.03.16 |
다시 시작하는 자바스크립트 - 내장객체 (0) | 2023.03.15 |
github : https://github.com/dnjfht
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!