본문 바로가기
웹 개발/javascript

[TIL] 배열(Array) 메소드: length, push, pop, shift, unshift, Array.isArray, indexOf, includes, concat, join, slice

by 스토리라이언 2021. 3. 9.

javascript의 배열에 대해 정리해 보자

배열은 무엇인가? 한 마디로 순서가 있는 값이다. 

let arr = [ 1, 2, 3, 4, 5];

대괄호(square bracket)를 이용해 element들을 그 안에 넣고, comma로 각 element를 구분한다. 

 

배열에는 원본이 수정되는 메소드가 있고, 원본이 수정되지 않는 메소드가 있다.

  • 기존의 배열을 수정하는 메소드: push, pop, shift, unshift

  • 기존의 배열을 수정하지 않는(원본유지) 메소드: slice, split, join, concat

배열의 길이를 알기 위해서는 length를 사용하면 된다. 

let arr = [ 1, 2, 3, 4, 5];
arr.length; //5

push, pop, shift, unshift:

  • push는 맨 마지막에 element를 추가, pop()는 맨 마지막 element를 제거한다. 
  • unshift는 맨 처음에 element를 추가, shift는 맨 처음에 element를 제거한다. 

push() : 배열의 element를 맨 마지막 index에 추가한다. 

let arr = [ 1, 2, 3, 4, 5];
arr.push(100); 
arr; // [1,2,3,4,5,100]

 

함수와 객체, 배열을 typeof를 해 보면 전부 Object로 나온다. 주어진 것이 배열인지 알기 위해서는 Array.isArray를 사용하면 된다. 

typeof 111;          //"number"
typeof 'hello';      //"string"
typeof true;         //"boolean"

//null, 객체, 배열의 type은 전부 object이다. 
typeof null;         //"object"
typeof [];           //"object"
typeof {};           //"object"

typeof function(){}  //"function"
typeof undefined;    //"undefined"

오늘 코플릿 문제를 풀면서 가장 힘들었던 부분이 join과 concat, split부분이었다. 그 부분을 중점적으로 정리해본다. 

 

join() : 배열의 모든 요소를 연결해 하나의 문자열을 만든다. 구분자 separator는 생략가능하고 기본 구분자는 콤마(',')

arr.join([separator])

const elements = ['Fire', 'Air', 'Water'];

console.log(elements.join());   // "Fire,Air,Water"

console.log(elements.join('')); // "FireAirWater"

console.log(elements.join('-'));// "Fire-Air-Water"

////////////////////////
let arr = [1,2,3,4];

arr.join();     // "1,2,3,4" 배열을 문자열로 전환시킨 후 기본구문자 ','로 연결한 문자열을 반환한다
arr.join('');   // "1234"    문자열로 전환시킨후 빈문자열로 연결한 문자열을 반환한다.
arr.join(':');  // "1:2:3:4" 문자열로 전환시킨후 ':'로 연결한 문자열을 반환한다
arr.join('-');  // "1-2-3-4" 문자열로 전환시킨후 '-'로 연결한 문자열을 반환한다. 

기본구분자가 ','이기 때문에 join()에 ( )안에 separator가 없어도 ','로 조인된다. 

 

다음의 문제를 생각해 보자.

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

arr를 다음과 같은 문자열로 반환하려면 어떻게 해야 할까?  join를 사용해서 생각해 보자
 '(010)1234-5678'

풀이

더보기

1. [0,1,0 ...] 을 (010)으로 전환해야 한다. 

  1-1. slice를 사용해서 arr에서 [0,1,0]을 잘라낸다.

  arr.slice(0,3);

 

 1-2. 배열을 문자열로 전환한 후 빈문자열로 연결한 문자열을 반환해야 한다. 

  0,1,0을 010으로 전환하려면 join('')을 사용하면 된다. 원래 조인의 parameter로 separator가 들어가야 하는데 생략한 경우, 기본 구분자(separator)는 ','이다. 그런데 join('')을 하게 되면 그 콤마(',')가 사라지고 010과 같이 연결된 문자열로 결합하게 된다. 

arr.slice(0,3).join('');

 

 1-3. template literal를 사용해서 '(010)'의 형태로 전환한다. 

let first = `(${arr.slice(0,3).join('')})`;

 

2. [0,1,0,1,2,3,4,5,6,7,8]를 1234-5678로 전환해야 한다. 

 2-1. arr.slice와 join을 통해 [1,2,3,4]을 1234로 만든다. 

  let body = arr.slice(3,7);

  let tali = arr.slice(7);

 

 2-2. first, body와 tail를 template literal로 연결한다.

 return `${first}${body}-${tail}`; 

 

concat: 인수로 전달된 값을 원본 배열의 마지막에 추가한 새로운 배열을 반환한다. 배열인 경우 배열을 해체하고 새로운 배열의 element를 추가한다. 원본은 변경되지 않는다. 

let arr1 = [1,2];
let arr2 = [3,4];

[1,2,3,4]로 만들려면 어떻게 해야 할까?

arr1.concat(arr2); // [1,2,3,4]

//만약 arr1에 3을 추가하고 싶으면 concat를 사용해서 어떻게 해야할까?
arr1.concat(3); // [1,2,3]

//arr1 원본 배열은 변경되지 않는다. 
arr1; // [1,2]
let hege = ["Cecilie", "Lone"];
let stale = ["Emil", "Tobias", "Linus"];
let children = hege.concat(stale);

console.log(children); //["Cecilie", "Lone", "Emil", "Tobias", "Linus"]

concat메소드 대신 push나 unshift 메소드를 사용할 수 있다. 다음과 같은 차이가 있다. 

  • push나 unshift는 원본 배열을 변경하지만 concat는 원본 배열을 변경하지 않고 새로운 배열을 반환한다
  • 인수로 전달받은 값이 배열인 경우, push나 unshift는 배열을 그대로 원본 배열의 마지막/첫번째 요소에 추가하지만, concat는 인수로 전달받은 배열을 해체하고 새로운 배열의 마지막 요소에 추가한다. 
//push, unshift는 인수로 전달받은 배열을 그대로 원본 배열의 element로 추가한다. 
let arr = [3,4];

arr.unshift([1,2]);
arr.push([5,6]);

arr;     //[[1,2],3,4,[5,6]]

//concat메소드는 인수로 전달받은 배열을 해체하고 새로운 배열의 element로 추가한다
let result = [1,2].concat([3,4]);
result = result.concat([5,6]);

result;  // [1,2,3,4,5,6]

ES6에서 concat대신 spread syntax 문법으로 대체할 수 있다.

let result = [1,2].concat([3,4]);

result; // [1,2,3,4]

//concat메소드는 spread 문법으로 대체할 수 있다. 
result = [ ...[1,2], ...[3,4]];
result; // [1,2,3,4]

 

slice(start, end) : 인수로 전달된 범위의 요소를 복사하여 배열로 반환한다. 원본 배열은 변경되지 않는다. 

let arr = [1,2,3,4,5];

//start는 포함하고 end는 포함하지 않고 이전까지 복사하여 반환한다. 
arr.slice(0,2);   // [1,2]

//end가 없으면 arr[1]이후 모든 요소를 복사하여 반환한다. 
arr.slice(1);     // [2,3,4,5]

//start에 음수가 들어올 수 있다. 숫자만큼 배열의 마지막 element를 반환한다. 
arr.slice(-1);    // [5]
arr.slice(-2);    // [4,5]

slice메서드의 인수를 생략하면 원본 배열의 복사본을 생성하여 반환한다. 

let arr = [1,2,3];

let result = arr.slice();
console.log(result);    // [1,2,3]
//이때 생성된 복사본은 얕은 복사(shallow copy)

문제: 함수 addToBackOfNew를 생각해 보자. 이 함수는 [1,2]와 같은 array에 추가할 element 3를 배열 맨 뒤에 새로운 배열을 담는 것이다. (단, 입력받은 배열은 변경되지 않아야 합니다)

let arr = [1,2];

let output = addToBackOfNew(arr, 3); 일때

[1,2,3] 이렇게 새로운 배열을 리턴하려면 어떻게 해야 할까?

function addToBackOfNew(arr, element) {
 //to-do
}

 

풀이

더보기

맨 뒤에 새로운 element를 추가하려면 push를 사용하면 된다. 

function addToBackOfNew(arr, element) {
   return arr.push(element);
}

arr; // [1,2,3] 이 된다. 그런데 이렇게 하면 안된다. 

문제의 조건 중에 원본이 수정되지 않아야 한다고 하는데 원본은 [1,2]인데 새로운 배열은 arr이 [1,2,3]으로 변경되었다. 

그렇다면 어떻게 하면 원본을 변경하지 않고 element를 배열의 맨 뒤에 추가할 수 있을까?

 

여기에서 활용할 수 있는 것이 바로 arr.slice() 이다. arr.slice()는 얕은 복사(shallow copy)가 된다. 

 

arr.slice()를 활용하여 수정해 보면 다음과 같다. 

 

function addToBackOfNew(arr, element) {

 //새로운 배열을 담을 변수에 arr.slice()를 할당한다.

   let newArr = arr.slice(); // arr.slice()는 arr안의 모든 element를 복사한다. 
   return newArr.push(element);
}

댓글