[개발자의품격][부트캠프][1기][8차시] JavaScript 주요 포인트 #4 | 내장 객체 - Array 객체
JavaScript 주요 포인트 #4
내장 객체 - Array 객체
Array 객체는 실무에서 많이 사용하는 매우 중요한 객체이다.
join
<script>
let brands = ["애플", "구글", "메타", "아마존", "네이버", "카카오"];
// join()은 배열의 문자열을 하나의 문자열로 결합하며, 실무에서 많이 사용한다.
console.log(brands.join(", ")); // 구글, 메타, 아마존, 네이버, 카카오
</script>
join은 배열의 문자열을 하나의 문자열로 결합하는 기능으로서 실무에서 많이 사용한다. 아래의 코드는 좀 더 구체적인 예이다.
<button onclick="doSearch()">조회</button>
<table>
<thead>
<tr>
<th>음료</th>
<th>가격</th>
</tr>
</thead>
<tbody id="table1Tbody"></tbody>
</table>
<script>
function doSearch() {
const productList = [
// 음료 리스트
{
name: "솔의눈",
price: 700,
},
{
name: "커피",
price: 700,
},
{
name: "파워레이드",
price: 1200,
},
{
name: "오렌지",
price: 1000,
},
{
name: "보리차",
price: 1200,
},
{
name: "밀키스",
price: 800,
},
];
}
// += 연산자를 이용한 문자열 결합
// let h = "";
// for (const product of productList) {
// h += "<tr>";
// h += "<td>" + product.name + "</td>";
// h += "<td>" + product.price + "</td>";
// h += "</tr>";
// }
// document.getElementById("table1Tbody").innerHTML = h;
// 많은 데이터를 다룰 때는 문자열 결합을 사용하지는 않고, 배열에 push하는 방식을 이용한다.
let h = [];
for (const product of productList) {
h.push("<tr>");
h.push("<td>" + product.name + "</td>");
h.push("<td>" + product.price + "</td>");
h.push("</tr>");
}
// for문 결과 배열 h의 값은 ['<tr>', '<td>솔의눈</td>', '<td>700</td>', '</tr>', '<tr>', '<td>커피</td>', '<td>700</td>', '</tr>', '<tr>', '<td>파워레이드</td>', '<td>1200</td>', '</tr>', '<tr>', '<td>오렌지</td>', '<td>1000</td>', '</tr>', '<tr>', '<td>보리차</td>', '<td>1200</td>', '</tr>', '<tr>', '<td>밀키스</td>', '<td>800</td>', '</tr>']
// join 함수를 이용해 문자열로 결합하여 화면에 출력할 html 코드를 완성한다.
document.getElementById("table1Tbody").innerHTML = h.join("");
</script>
많은 데이터를 다룰 때는 배열에 push한 후 join 함수를 이용해 문자열로 결합니다. 결합되는 양이 적을 때는 +=을 이용한 문자열 결합이 빠르지만, DB에서 데이터를 불러오는 경우라면 상황이 달라진다. 몇천에서 몇만 건이 넘어가는 데이터는 배열을 이용하는 것이 성능면에서 훨씬 유리하다. [그림 1]은 위 코드의 실행 결과이다. 조회 버튼을 누르면 데이터가 표시된다.
pop / shift
<script>
let brands = ["애플", "구글", "메타", "아마존", "네이버", "카카오"];
// pop() 배열의 마지막 인덱스의 요소를 제거하고 반환
console.log(brands.pop()); // 카카오
// shift() 배열의 0번 인덱스의 요소를 제거하고 반환(실무에서는 shift를 pop보다 훨씬 많이 사용함)
console.log(brands.shift()); // 애플
// shift는 큐를 만들어 사용할 때 유용하다. 사용자의 요청이 들어올때마다 처리해야하는 값이 계속 배열의 마지막 인덱스에 push되고, 동시에 0번 인덱스의 값을 처리할때 쓰인다.
// let eventQueue = [];
// eventQueue.shift();
</script>
실무에서는 shift를 pop 보다 더 많이 사용한다. 주로 서버로부터 대량의 고객 연락처(또는 이메일 주소)를 가져와 문자 메시지(또는 이메일)를 발송하는 기능을 구현할 때 이용한다. 또한 큐를 다룰 때 유용하다.
unshift
<script>
let brands = ["애플", "구글", "메타", "아마존", "네이버", "카카오"];
brands.unshift("삼성전자");
console.log(brands); // ['삼성전자', '애플', '구글', '메타', '아마존', '네이버', '카카오']
</script>
unshift는 배열의 0번 인덱스에 요소를 추가하고 배열 길이를 반환한다.
<body>
<select name="" id="city"></select>
// 이 코드에서는 라인 "추가, 삭제" 버튼의 기능을 구현하지 않았지만, 자바스크립트를 이용해 리스트 박스의 라인을 추가, 삭제하는 기능을 구현할 수 있다.
<button>라인추가</button>
<button>라인삭제</button>
<script>
// unshift 함수는 실무에서 리스트 박스를 이용해 검색하는 기능을 만들때 주로 사용한다.
function loadCity(needAll) {
let cities = [
{ code: "02", title: "서울" },
{ code: "21", title: "부산" },
{ code: "064", title: "제주" },
];
let h = [];
// 배열 h에 리스트 cities의 각 오브젝트를 push
for (const city of cities) {
h.push(
'<option value="' + city.code + '">' + city.title + "</option>"
);
}
// needAll이 참일 때 배열 h의 0번 인덱스에 요소를 추가한다. 해당 값은 리스트 박스의 최상단에 표시된다.
if (needAll) {
h.unshift('<option value="">==전체==</option>');
}
document.getElementById("city").innerHTML = h.join("");
}
loadCity(1);
</script>
</body>
unshift 함수는 실무에서 리스트 박스를 이용해 검색하는 기능을 만들때 주로 사용한다. 개발자들 중 자바스크립트 내장 함수를 잘 알고 있으면 쉽게 해결할 수 있는 문제를 어렵게 해결하는 경우가 많은데 리스트 박스의 구현도 그중 하나이다. 위 코드를 보면 for 문을 통해 리스트 cities 내에 있는 각 오브젝트가 배열 h에 push된다. 그 후 unshift 함수에 의해 배열 h의 0번 인덱스에 값이 추가된다. 해당 값은 [그림 2]와 같이 리스트 박스의 최상단에 위치하게 된다. unshift 함수를 "라인 추가" 버튼과 연결하면 리스트 박스의 최상단에 새로운 라인을 추가하는 버튼을 구현할 수 있다.
splice
<script>
let brands = ["애플", "구글", "메타", "아마존", "네이버", "카카오"];
brands.splice(1, 0, "리턴벨류", "더그레잇"); // 1번 파라미터는 새로운 요소를 추가할 인덱스 번호, 2번 파라미터는 1번 파라미터 인덱스 번호에서 부터 삭제할 요소 수, 나머지 파라미터는 추가할 요소
console.log(brands); // ['애플', '리턴벨류', '더그레잇', '구글', '메타', '아마존', '네이버', '카카오']
</script>
splice 함수는 실무에서 마치 엑셀에서 행이나 열을 삽입하듯이 처리할때 유용하다. 실무에서 splice를 사용하면 쉽게 구현할 수 있는 기능을 if 문을 이용해 하드 코딩하는 경우가 있다. 좋은 개발자는 내장 함수를 잘 이해하고 있어야 할 뿐만 아니라 응용할 수 있어야 한다.
concat
<script>
// concat
let arr1 = ["A", "B"];
let arr2 = ["C", "D"];
let arr3 = ["E", "F", "G"];
let arr4 = arr1.concat(arr2, arr3);
console.log(arr4); // ['A', 'B', 'C', 'D', 'E', 'F', 'G']
// 실무에서는 이 방법을 더 많이 사용한다.
let arr5 = [...arr1, ...arr2, ...arr3];
console.log(arr5); // ['A', 'B', 'C', 'D', 'E', 'F', 'G']
</script>
2개 이상의 배열을 하나로 결합한다. 실무에서는 concat보다는 리스트 안에서 ...을 더 많이 사용한다.
slice
<script>
let arr = ["A", "B", "C", "D", "E", "F", "G"];
// slice(시작인덱스, 종료인덱스)
console.log(arr.slice(1, 2)); // ['B']
</script>
문자열 slice와 같은 개념이다. 멘토님은 실무에서 그다지 사용하지 않았다고 한다.
sort
<script>
let brands = ["애플", "구글", "메타", "아마존", "네이버", "카카오"];
// 가나다순 정렬
console.log(brands.sort()); // ['구글', '네이버', '메타', '아마존', '애플', '카카오']
let points = [40, 100, 1, 5, 25, 10];
console.log(points.sort()); // [1, 10, 100, 25, 40, 5], sort는 숫자를 문자열로 이해하고 정렬한다.
</script>
sort 함수는 실무에서 많이 사용한다. 기본적으로 가나다순으로 정렬한다. 정수도 문자열로 인식하고 정렬하기 때문에 주의해야 한다.
<script>
let points = [40, 100, 1, 5, 25, 10];
// 내장함수 sort의 원리를 이용해 정수를 오름차순(또는 내림차순) 정렬할 수 있다.
// sort 원리: 비교하는 값의 차가 양수이면 위치 바꾸고, 음수이면 그대로 둔다.
function numberSortAsc(a, b) {
// a = 40, b = 100 -> -60(음수 값이면 위치를 바꾸지 않음)
// a = 100, b = 1 -> 99(양수 값이면 위치를 바꿈)
// ~ 계속 돌면서 처리. 더 이상 변경되지 않으면 종료
return a - b; // 오름차순
}
console.log(points.sort(numberSortAsc)); // [1, 5, 10, 25, 40, 100]
function numberSortDes(a, b) {
// a = 40, b = 100 -> 60(양수 값이면 위치를 바꿈)
// a = 40, b = 1 -> -39(음수 값이면 위치를 바꾸지 않음)
// ~ 계속 돌면서 처리. 더 이상 변경되지 않으면 종료.
return b - a; // 내림차순
}
console.log(points.sort(numberSortDes)); // [100, 40, 25, 10, 5, 1]
</script>
정수로 구성된 배열을 정렬하는 방법은 위의 코드와 같다. sort 함수의 원리를 이용해 정수를 오름차순(또는 내림차순) 정렬할 수 있다. sort 원리는 이터러블(iterable) 객체를 0번 인덱스부터 시작해 두 요소를 비교하여 값의 차가 양수이면 위치 바꾸고, 음수이면 그대로 둔다.
<script>
const productList = [
// 음료 리스트
{
name: "솔의눈",
price: 700,
},
{
name: "커피",
price: 700,
},
{
name: "파워레이드",
price: 1200,
},
{
name: "오렌지",
price: 1000,
},
{
name: "가봉",
price: 1000,
},
{
name: "보리차",
price: 1200,
},
{
name: "밀키스",
price: 800,
},
];
// 오브젝트의 name을 기준으로 정렬
// function objectSort(a, b) {
// if (a.name > b.name) return 1;
// else if (a.name < b.name) return -1;
// else return 0;
// }
// console.log(productList.sort(objectSort)); // 결과는 [그림 3] 왼쪽 참조
// 오브젝트의 price를 기준으로 정렬
// function priceSort(a, b) {
// if (a.price > b.price) return 1;
// else if (a.price < b.price) return -1;
// else return 0;
// }
// console.log(productList.sort(priceSort)); // 결과는 [그림 3] 중간 참조
// 오브젝트의 price 기준으로 정렬하고, price가 같으면 name 기준으로 정렬
function twoFieldSort(a, b) {
if (a.price > b.price) return 1;
else if (a.price < b.price) return -1;
else {
if (a.name > b.name) return 1;
else if (a.name < b.name) return -1;
else return 0;
}
}
console.log(productList.sort(twoFieldSort)); // 결과는 [그림 3] 오른쪽 참조
</script>
sort의 양수, 음수 여부에 따른 위치 바꿈의 원리를 이용해 리스트 내 오브젝트를 정렬할 수 있다.
filter
<script>
const productList = [
// 음료 리스트
{
name: "솔의눈",
price: 700,
},
{
name: "커피",
price: 700,
},
{
name: "파워레이드",
price: 1200,
},
{
name: "오렌지",
price: 1000,
},
{
name: "가봉",
price: 1000,
},
{
name: "보리차",
price: 1200,
},
{
name: "밀키스",
price: 800,
},
];
// if문 사용
newProductList = [];
const inputCoin = 1000; // 1000원 이하만 필터링
for (const product of productList) {
if (product.price <= inputCoin) {
newProductList.push(product);
}
}
console.log(newProductList);
// filter 사용 1
function doFilter(product) {
// if (product.price <= inputCoin) {
// return true;
// } else {
// return false;
// }
return product.price <= inputCoin ? true : false;
}
newProductList = productList.filter(doFilter);
console.log(newProductList);
// filter 사용 2
newProductList = productList.filter(function (p) {
return p.price <= inputCoin ? true : false;
});
console.log(newProductList);
// filter 사용 3 - 화살표 함수 사용 1
newProductList = productList.filter((p) =>
p.price <= inputCoin ? true : false
);
console.log(newProductList);
// filter 사용 4 - 화살표 함수 사용 2
console.log(productList.filter((p) => p.price <= inputCoin));
</script>
filter 함수는 실무에서 조회시 매우 많이 사용한다. 특히 화살표 함수와 함께 사용하는 경우를 눈여겨보자!
map
<script>
let userList = [
{
firstName: "재석",
lastName: "유",
email: "yu@gmail.com",
},
{
firstName: "종국",
lastName: "김",
email: "kim@gmail.com",
},
{
firstName: "흥국",
lastName: "김",
email: "kim@gmail.com",
},
{
firstName: "세찬",
lastName: "양",
email: "yang@gmail.com",
},
{
firstName: "석진",
lastName: "지",
email: "ji@gmail.com",
},
];
function newUserMap(user) {
return {
// firstName: user.firstName,
// lastName: user.lastName,
email: user.email,
fullName: user.lastName + user.firstName,
};
}
let userList2 = userList.map(newUserMap);
console.log(userList2);
</script>
map 함수는 원하는 오브젝트를 새롭게 만들 때 유용하다. 서버에서 데이터를 받아올 때 map을 이용해 원하는 데이터를 가공해 가져올 수 있다. 쿼리를 사용하는 경우도 있지만 데이터 패킷 부담을 줄이는 등 이 방법이 효율적일 수 있다.
reduce
<script>
points = [80, 90, 95, 78, 88, 100, 92];
let sum = points.reduce(function (
accumulator, // 누적값
currentValue, // 현재 배열 요소
currentIndex, // 현재 배열 인덱스 번호
arr // 전체 배열
) {
return accumulator + currentValue;
// return currentIndex; //6
// return arr; // [80, 90, 95, 78, 88, 100, 92]
}, 0); //누적값의 처음값 0
console.log(sum); // 623
const productList = [
// 음료 리스트
{
name: "솔의눈",
price: 700,
},
{
name: "커피",
price: 700,
},
{
name: "파워레이드",
price: 1200,
},
{
name: "오렌지",
price: 1000,
},
{
name: "가봉",
price: 1000,
},
{
name: "보리차",
price: 1200,
},
{
name: "밀키스",
price: 800,
},
];
// price 합계
let sum1 = productList.reduce(function (
// 파라미터명은 변경해도 무관, 순서는 지켜야 함
accumulator, // 누적값
currentValue, // 현재 배열 요소, 일반적으로 누적값과 현재 배열 요소만 사용함
currentIndex, //현재 배열 인덱스 번호
arr // 전체 배열
) {
return accumulator + currentValue.price;
}, 0);
console.log(sum1); // 6600
// 1000상위인 price 합계
let sum2 = productList.reduce(function (total, product) {
if (product.price > 1000) {
return total + product.price;
} else {
return total;
}
// return total + product.price;
}, 0);
console.log(sum2); // 2400
// 리스트 내 문자열 누적
let alphabets = ["A", "B", "C"];
let alphabetString = alphabets.reduce(function (alpha, c) {
return alpha + c;
}, ""); // ""는 누적값의 처음 문자열 값
console.log(alphabetString); // ABC
</script>
reduce를 이용해 배열의 합계를 쉽게 구할 수 있다. 배열에 담긴 데이터를 하나씩 순회하며 callback 함수의 실행 값을 누적하여 결괏값을 반환한다. 멘토님의 경우에는 문자열 누적보다는 숫자의 합계를 구할 때 주로 사용했다고 한다.