자바스크립트 코딩의 기술_배열로 데이터 관리하기
자바스크립트 2021. 5. 22. 15:10(본 포스팅은 길벗의 '자바스크립트-코딩의 기술' 책을 공부하면서 작성되었습니다_내돈내산)
1. 배열로 유연한 컬렉션을 생성하라
- 원래 자바스크립트에는 데이터 컬렉션을 다루는 구조로 배열과 객체 두가지만 있었다. 하지만 모던 자바스크립트로 넘어오면서 맵(Map), 세트(Set), 위크 맵(WeakMap), 위크셋(WeakSet) 이 추가되었다.
- 어떤 형태로든 조작(추가, 제거, 정렬, 필터링, 교체 등) 해야한다면 배열이 가장 적합한 컬렉션이 될것임.
- 객체를 순회하려면 먼저 Object.Keys() 를 실행해서 객체의 키를 배열에 담은 후 생성한 배열을 이용해 배열을 객체와 반복문의 가교로 활용하여 순회한다.(아래 예시)
function getTotalStats() {
// # START:loop
const game1 = {
player: 'Jim Jonas',
hits: 2,
runs: 1,
errors: 0,
};
const game2 = {
player: 'Jim Jonas',
hits: 3,
runs: 0,
errors: 1,
};
const total = {};
const stats = Object.keys(game1); // *****
for (let i = 0; i < stats.length; i++) { // *****
const stat = stats[i]; // *****
if (stat !== 'player') { // *****
total[stat] = game1[stat] + game2[stat]; // *****
} // *****
} // *****
// {
// hits: 5,
// runs: 1,
// errors: 1
// }
// # END:loop
return total;
}
- 배열에는 iterable이 내장되어 있어 컬렉션의 항목을 한번에 하나씩 처리하는 것이 가능함. 그래서 다양한 분야에 많이 쓰고 있음.
2. Include( ) 로 존재 여부를 확인하라
- include() 메서드를 통해 배열에 있는 값의 위치를 확인하지 않고 존재여부를 확인할 수 있음.
- 존재여부를 확인하는 것은 삼항연산자와 단락평가를 비롯해 대부분의 조건문에서 중요하게 작용한다.
- 자바스크립트에서 배열이 특정문자열을 포함하고 있는지 확인하려면 문자의 위치를 찾아내야 하는데, 특정문자열이 존재하면 해당 문자열의 index 값을 이용해 위치를 확인할 수 있다. 하지만 문제는 index값이 0 이 되어버리면 자바스크립트에서는 이를 false로 평가해버린다. 이때문에 존재하는 값이어도 false를 반환할 수 있는 문제가 있다. 다음과같은 예시가 그렇다.
const sections = ['shipping'];
function displayShipping(sections) {
if (sections.indexOf('shipping')) {
return true;
}
return false;
}
- 이와같은 상황을 해결하기 위해 -1 값을 이용한 조건문을 구현해야 하는 번거로움이 있었음.
const sections = ['contact', 'shipping'];
function displayShipping(sections) {
return sections.indexOf('shipping') > -1;
}
- 이러한 번거로움을 해결하기 위해 ES2016에서 추가된 새로운 기능인 include( )를 이용해서 존재여부에 따라 boolean값으로 true 또는 false를 반환하도록 한다. (색인이 0인경우 false를 반환하는 문제 해결)
const sections = ['contact', 'shipping'];
function displayShipping(sections) {
return sections.includes('shipping');
}
3. 펼침연산자(spread, ....) 로 배열을 본떠라
- 펼침연산자는 마침표 세개(...)로 표시하며, 배열에 포함된 항목을 목록으로 바꿔주는 역할을 한다.
- 맵, 매개변수, 제너레이터 등 다양한 부분에 사용이 가능함.
const cart = ['Naming and Necessity', 'Alice in Wonderland']
...cart // 이렇게 사용할 경우 오류가 발생함. 펼침연산자를 단독으로 사용할 수 없음.
const copyCart = [...cart]; // 이런식으로 정보를 어디에든 펼쳐 넣어야 한다.
- 다음 예시를 통해 펼침연산자가 어떤식으로 쓰일 수 있는지 알아볼 수 있다.
// 반복문 이용
function removeItem(items, removable) {
const updated = [];
for (let i = 0; i < items.length; i++) {
if (items[i] !== removable) {
updated.push(items[i]);
}
}
return updated;
}
// 배열메서드인 splice( ) 사용
function removeItem(items, removable) {
if (items.includes(removable)) {
const index = items.indexOf(removable);
items.splice(index, 1);
}
return items;
}
const books = ['practical vim', 'moby dick', 'the dark tower'];
const recent = removeItem(books, 'moby dick');
const novels = removeItem(books, 'practical vim');
- 첫번째는 배열에서 항목을 제거하기 위해 반복문을 사용한 예시이다. 하지만 코드가 복잡하고 어수선하기 때문에 배열메서드인 splice()를 사용해서 리팩토링을 거쳐 두번째 코드가 탄생했다.
- 하지만 첫번째 removeItem( )에 books라는 배열을 전달하여 'moby dick'을 제거한 배열을 반환받는과정에서 원본배열인 books도 함께 변경되었다.
- 함수에 전달하는 정보가 근본적으로 달라지는것이 매우 안좋은 현상이 발생한다.
// 배열메서드인 slice() 사용
function removeItem(items, removable) {
if (items.includes(removable)) {
const index = items.indexOf(removable);
return items.slice(0, index).concat(items.slice(index + 1));
}
return items;
}
- 위의 현상을 개선하기 위해 원본배열을 변경하지 않고 배열의 일부를 반환하는 배열메서드인 slice()를 사용하였다.
- 하지만 코드의 가독성이 떨어지고, concat이 배열 두개를 병합한다는 의미를 알고 있어야 코드를 이해할 수 있다.
// 펼침연산자(spread)를 이용한 코드 구현
function removeItem(items, removable) {
if (items.includes(removable)) {
const index = items.indexOf(removable);
return [...items.slice(0, index), ...items.slice(index + 1)];
}
return items;
}
- 펼침 연산자를 이용해 코드를 구현하였을때, 일단 데이터의 조작이 일어나지 않았고, 읽기 쉽고 간편해졌다. 재사용할수 있으며, 직관적으로 코드를 이해할 수 있게 변했다.
// # START:spreadArguments
const book = ['Reasons and Persons', 'Derek Parfit', 19.99];
function formatBook(title, author, price) {
return `${title} by ${author} $${price}`;
}
// # END:spreadArguments
// # START:spreadArgumentsExample
formatBook(book[0], book[1], book[2]);
// # END:spreadArgumentsExample
// # START:spreadArgumentsExample2
formatBook(...book);
// # END:spreadArgumentsExample2
- 위에서 볼 수 있듯이 formatBook처럼 목록을 인수로 받아 반환하는 함수가 있다. 그리고 그 목록이 순서대로 들어간 배열값이 존재한다고 할때. 펼침연산자를 이용해 그 배열을 목록화 시키는 기능을 이용할 수 있다.
4. push( ) 메서드 대신 펼침연산자로 원본 변경을 피하라
- 코드에서 원본데이터의 조작이 발생한 경우 예상치 못한 결과를 낳을 수 있는 가능성이 증가한다.
- 모던 자바스크립트의 상당수가 함수형 프로그래밍 형식을 취하기 때문에 기타 효과와 조작이 없는 코드를 작성해야 한다.
- 우리가 가장 흔하게 사용하는 배열메서드 중 push( )라는 메서드가 있다. 이는 새로운 항목을 배열뒤에 추가해 원본배열을 변경하는 메서드이다.
- 이는 순수함수(pure function)을 만드는데 있어서 문제가 될 수 있다.(순수함수: 함수에 부수적인 효과가 없는 것)
// # START:titles
const titles = ['Moby Dick', 'White Teeth'];
const moreTitles = [...titles, 'The Conscious Mind']; // title.push('The Conscious Mind')
// ['Moby Dick', 'White Teeth', 'The Conscious Mind'];
// # END:titles
}
function forgetting() {
// # START:forgetting
// Add to beginning.
const titles = ['Moby Dick', 'White Teeth'];
titles.shift('The Conscious Mind'); // 원본배열 변경, slice의 기능을 명확히 알아야 이해 가능
const moreTitles = ['Moby Dick', 'White Teeth'];
const evenMoreTitles = ['The Conscious Mind', ...moreTitles]; // 새로운 배열로 원본배열 조작없음.
// Copy
const toCopy = ['Moby Dick', 'White Teeth'];
const copied = toCopy.slice();
const moreCopies = ['Moby Dick', 'White Teeth'];
const moreCopied = [...moreCopies];
// # END:forgetting
5. 펼침연산자로 정렬에 의한 혼란을 피하라
- 배열을 여러번 정렬해도 항상 같은 결과가 나올 수 있도록 펼침연산자를 사용할 수 있다.
- 펼침연산자로 여러가지 조작함수를 대체할 수 있다고 설명했다. 하지만 대체 불가능한 함수가 있을 때는 어떤 방법을 사용하는 것이 좋을까. 답은 펼침연산자로 원본 배열의 사본을 생성하고, 사본을 조작하면 된다.
- 자바스크립트의 정렬함수 중 sort( )라는 함수가 있다. 이 함수는 원본배열의 순서를 변경해서 원본을 참조하는 값을 반환하게 된다.
// (1) 원본배열
const staff = [
{
name: 'Joe',
years: 10,
},
{
name: 'Theo',
years: 5,
},
{
name: 'Dyan',
years: 10,
},
];
// (2) years를 오름차순으로 정렬한 배열
// [
// {
// name: 'Theo',
// years: 5
// },
// {
// name: 'Joe',
// years: 10
// },
// {
// name: 'Dyan',
// years: 10
// },
// ];
// (3) (2)결과를 이름순으로 정렬한 배열
// [
// {
// name: 'Dyan',
// years: 10
// },
// {
// name: 'Joe',
// years: 10
// },
// {
// name: 'Theo',
// years: 5
// },
// ];
// (4) (3)결과를 다시 years 오름차순으로 정렬한경우
// [
// {
// name: 'Theo',
// years: 5
// },
// {
// name: 'Dyan',
// years: 10
// },
// {
// name: 'Joe',
// years: 10
// },
// ]
- 위의 결과를 보았을때, (2)번결과와 (4)번결과 모두 연도를 오름차순으로 배열한 결과인데 배열의 순서가 다르게 나오는것을 알 수 있다. 이는 sort를 이용해 원본배열이 변경되었기 때문이다. 정렬결과가 매번 바뀌게 된다면 그 결과에 대한 신뢰도가 하락하기 때문에 좋은 경우가 아니게 된다.
- 아래와같이 펼침연산자를 이용해 배열의 사본을 만들어 사본을 조작하면 위와같은 결과를 방지할 수 있다.
[...staff].sort(sortByYears);
// [
// {
// name: 'Theo',
// years: 5
// },
// {
// name: 'Joe',
// years: 10
// },
// {
// name: 'Dyan',
// years: 10
// },
// ];
'자바스크립트' 카테고리의 다른 글
자바스크립트 코딩의 기술_Collection으로 데이터 관리하기_2 (0) | 2021.05.23 |
---|---|
자바스크립트 코딩의 기술_Collection으로 데이터 관리하기_1 (0) | 2021.05.23 |
자바스크립트 코딩의 기술_변수할당 (0) | 2021.05.22 |
자바스크립트 입문_메서드 오버라이드, 프로토타입 체인 (0) | 2021.05.19 |
자바스크립트 입문_constructor 프로퍼티 (0) | 2021.05.19 |