자주 사용하는 🔑배열 메서드의 종류(5가지)를 알고서 잘 사용해보자!
1> 원본 배열을 직접 변경하는 메서드
2> 원본 배열을 직접 변경하지 않고 새로운 배열을 생성하여 반환하는 메서드
💡 원본 배열)
여기서 말하는 원본 배열이란 배열 메서드를 호출한 배열로 배열 메서드의 구현체 내부에서 this가 가리키는 객체를 말한다.
<script>
const arr = [1];
arr.push(2);
console.log(arr); // [1, 2] // 1> push 메서드는 원본 배열, arr를 직접 변경한다.
const result = arr.concat(3); // 2> concat 메서드는 원본 배열, arr을 직접 변경하지 않고 새로운 배열을 생성하여 반환한다.
console.log(arr); // [1, 2]
console.log(result); // [1, 2, 3]
</script>
-> 가급적 원본 배열을 직접 변경하지 않아
부수효과(외부 상태 변경)가 없는 메서드를 사용하는 것을 권장.
- Array.isArray 메서드는 Array 생성자 함수의 정적 메서드로 전달된 인수가 배열인지를 판단한다.
💡참고) 배열을 생성하는 Array.of, Array.from 메서드도 정적 메서드이다.
- Array.isArray 메서드는 전달된 인수가 배열이면 true, 아니면 false를 반환한다.
<script> // True Array.isArray([]); Array.isArray([new Arraay()]); // false Array.isArray({}); Array.isArray({0: 1, length: 1}); </script>
- indexOf 메서드는 원본 배열에서 인수로 전달된 요소를 검색하여 인덱스를 반환한다.
- 원본 배열에 인수로 전달한 요소와 중복되는 요소가 여러 개 있다면 첫 번째로 검색된 요소의 인덱스를 반환하고 존재하지 않는다면 -1을 반환한다.
<script> const arr = [1, 2, 3, 4]; // 배열 arr에서 요소 2를 검색해 첫 번째로 검색된 요소의 인덱스를 반환 arr.indexOf(2); // 1 // 배열 arr에 요소 4가 없으므로 -1 반환 arr.indexOf(4); // -1 // 두 번째 인수는 검색을 시작할 인덱스로 생략되면 처음부터 검색한다. arr.indexOf(2,2); // -1 </script>
- indexOf 메서드는 배열에 특정 요소 존재하는지 확인시 유용하다.
<script> const favFood = ['kimchi', 'ramen']; // food 배열에 'rice' 요소 존재여부 확인 if(food.indexOf('rice' == -1)) { favFood.push('rice') // food 배열에 'rice' 요소 없으면 추가 } console.log(favFood); // ['rice', 'kimchi', 'ramen'] </script>
- indexOf 메서드 보다는 Array.prototype.includes 메서드가 가독성이 좋긴하다.
<script> const favFood = ['kimchi', 'ramen']; // food 배열에 'rice' 요소 존재여부 확인 if(!food.includes('rice')) { favFood.push('rice') // food 배열에 'rice' 요소 없으면 추가 } console.log(favFood); // ['rice', 'kimchi', 'ramen'] </script>
3-1> Array.prototype.push
- push 메서드는 인수로 전달받은 모든 값을 원본 배열의 마지막 요소로 추가하여
직접 변경
하고 변경된 length 프로퍼티 값을 반환한다.<script> const arr = [1, 2] // 인수로 전달 받은 모든 값을 원본 배열 마지막 요소로 추가 let result = arr.push(3, 4); console.log(result); // 4, 변경된 length 값 반환 console.log(arr); // [1, 2, 3, 4], 원본 배열을 직접 변경 </script>
- push 메서드는 성능면에서 좋지 못해 추가할 마지막 요소가 '하나'라면 length 프로퍼티를 사용하여 배열의 마지막 요소에 직접 추가하는 것이 성능면에서 더 빠르다.
<script> const arr = [1, 2]; // arr.push(3, 4)과 동일한 처리하지만 더 빠르다. arr[arr.length] = 3; console.log(arr); // [1, 2, 3], 원본 배열을 직접 변경 </script>
- push 메서드는 원본 배열을 직접 변경하는 부수효과 때문에 ES6의 스프레드 문법을 사용을 권장한다.
- 스프레드 문법을 사용하면 함수 호출 없이 표현식으로 마지막 요소를 추가할 수 있고 부수 효과도 없다
<script> const arr = [1, 2]; // ES6 스프레드 문법 const newArr = [...arr, 3]; console.log(newArr); // [1, 2, 3] </script>
3-2>Array.prototype.pop
- pop 메서드는 원본 배열에서 마지막 요소를 제거하고 제거한 요소를 반환한다.
- 원본 배열이 빈 배열이면 undefined를 반환하고 push 메서드처럼
원본 배열을 직접 변경한다.
<script> const arr = [1, 2] // 원본 배열에서 마지막 요소를 제거 let result = arr.pop(); console.log(result); // 2 제거한 요소 반환 console.log(arr); // [1], 원본 배열을 직접 변경 </script>
[stack(스택)
]
- pop 메서드와 push 메서드를 사용해
stack(스택)
구현- stack이란 데이터를 마지막에 넣고 마지막에 밀어 넣은 데이터를 먼저 꺼내는 후입선출(LIFO-Lash in First out)방식의 자료구조이다.
- stack은 언제나 마지막에 넣은 최신 데이터를 먼저 취득한다.스택에 데이터를 밀어 넣는 것을
push
, 스택에서 데이터를 꺼내는 것을pop
라고한다.
4-1>Array.prototype.unshift
- unshift 메서드는 인수로 전달받은 모든 값을 원본 배열의 선두에 요소로 추가하여
'직접' 변경
하고 변경된 length 프로퍼티 값을 반환한다.<script> const arr = [1, 2] // 인수로 전달 받은 모든 값을 원본 배열 선두에 요소로 추가 let result = arr.unshift(3, 4); console.log(result); // 4, 변경된 length 값 반환 console.log(arr); // [3, 4, 1, 2], 원본 배열을 직접 변경 </script>
- unshift 메서드 역시 원본 배열을 직접 변경하는 부수효과로 인해 ES6의 스프레드 문법을 사용을 권장한다.
<script> const arr = [1, 2]; // ES6 스프레드 문법 const newArr = [3, ...arr]; console.log(newArr); // [3, 1, 2] </script>
4-2>Array.prototype.shift
- shift 메서드는 원본 배열에서 첫 번째 요소를 제거하고 제거한 요소를 반환한다.
- 원본 배열이 빈 배열이면 undefined를 반환하고
원본 배열을 직접 변경
한다.<script> const arr = [1, 2] // 원본 배열에서 마지막 요소를 제거 let result = arr.shift(); console.log(result); // 1 제거한 요소 반환 console.log(arr); // [2], 원본 배열을 직접 변경 </script>
-[queue(큐)]
- shift 메서드와 push 메서드를 사용해
queue(큐)
구현- queue는 데이터를 마지막에 밀어 넣고, 처음 데이터, 가장 먼저 밀어 넣은 데이터를 먼저 꺼내는 선입선출(FIFO-First In Last Out)방식의 자료구조이다.
-stack
: 언제나 마지막에 밀어 넣은 최신 데이터를 먼저 취득
-queue
: 언제나 데이터를 밀어 넣은 순서대로 취득한다.
첫 번째 요소를 제거하고 제거한 요소를 반환한다.**
- concat 메서드는 인수로 전달된 값들(배열 또는 원시값)을 원본 배열의 마지막 요소로 추가한 '새로운' 배열로 반환하고
원본 배열은 변경하지 않는다
.- 인수로 전달한 값이 배열이면 해체하여 새로운 배열의 요소로 추가한다.
<script> const arr1 = [1, 2] const arr2 = [3, 4] // arr2를 원본 배열 arr1의 마지막 요소로 추가한 새로운 배열 반환 let result = arr1.concat(arr2); console.log(result); // [1, 2, 3, 4] // 숫자를 원본 배열 arr1의 마지막 요소로 추가한 새로운 배열 반환 let result = arr1.concat(3); console.log(result); // [1, 2, 3] // 배열 arr2와 숫자를 원본 배열 arr1의 마지막 요소로 추가한 새로운 배열 반환 let result = arr1.concat(arr2, 5); console.log(result); // [1, 2, 3, 4, 5] console.log(arr1); // [1, 2], 원본 배열 변경되지 않음 </script>
- concat 메서드 역시 ES6의 스프레드 문법으로 대체가능하다.
<script> // concat 메서드는 인수로 전달받은 배열 해체하여 새로운 배열의 요소로 추가 let result = [1, 2].concat([3, 4]); console.log(result); // [1, 2, 3, 4] // concat 메서드도 ES6 스프레드 문법으로 대체가능 result = [...[1, 2], ...[3, 4]]; console.log(result); // [1, 2, 3, 4] </script>
push와 unshift 메소드는 concat 메소드로 대체할 수 있지만 미묘한 차이
가 있다.
1>차이(1)
1> push와 unshift 메소드는
원본 배열을 직접 변경
하지만
2> concat 메서드는원본 배열 변경하지 않고
새로운 배열을 반환한다.
- 1> push와 unshift 메소드를 사용하기 위해선 원본 배열을 반드시 배열에 저장해야하고
- 2> concat 메서드를 사용할 경우 반환값을 반드시 변수에 할당해야한다.
- 1> push와 unshift 메소드
<script> const arr1 = [3, 4] // unshift 메소드는 원본 배열을 직접 변경해 원본 배열을 저장해 두지 않으면 변경된 배열 사용할 수 없다. arr1.unshift(1, 2); // 원본 배열을 저장해 두어야 결과 확인 가능 console.log(arr1); // [1, 2, 3, 4] // push 메소드도 원본 배열을 직접 변경해 원본 배열을 저장해 두지 않으면 변경된 배열 사용할 수 없다. arr1.push(5, 6); // 원본 배열을 저장해 두어야 결과 확인 가능 console.log(arr1); // [1, 2, 3, 4, 5, 6] </script>
- 2>concat 메서드
<script> const arr2 = [3, 4]; // concat 메소드는 원본 배열을 변경하지 않고 새로운 배열을 반환 // arr1.unshift(1, 2) 대체 가능 let result = [1, 2].concat(arr2);// 반환값 변수에 할당해야 결과 확인 가능 console.log(result); // [1, 2, 3, 4] //arr1.push(5, 6) 대체 가능 // 숫자값을 result의 마지막 요소로 추가한 새로운 배열 반환 result = result.concat(5, 6); console.log(result); // [1, 2, 3, 4, 5, 6] </script>
2>차이(2)
인수로 전달받은 값이 배열인 경우
1> push와 unshift 메소드는배열 그대로 원본 배열의 마지막/첫 번째 요소로 추가
하지만
2> concat 메서드는 전달받은배열을 해체하여 마지막 요소로 추가
한다.
1> push와 unshift 메소드와 2> concat 메서드 배열을 인수로 전달
<script> const arr = [3, 4]; // unshift와 push 메소드는 인수로 전달받은 배열 그대로 원본의 배열 요소로 추가 arr.unshift([1, 2]) arr.push([5, 6]) console.log(arr); // [[1, 2] ,3, 4. [5, 6]] // concat 메서드는 인수로 전달받은 배열 해체하여 새로운 배열의 요소로 추가 let result = [1, 2].concat([3, 4]); result = result.concat([5, 6]) console.log(result); // [1, 2, 3, 4, 5, 6] </script>
💡TIP!)
- push/unshift 메서드, concat 메서드를 번갈아 쓰기 보단
ES6의 스프레드 문법을 일관성 있게 쓰는걸 권장!
원본 배열을 직접 변경
하는 메서드로 원본 배열의 처음/마지막에 요소를 추가하거나 제거한다.
- splice 메서드는 원본 배열의 중간에 요소를 추가하거나 중간에 있는 요소를 제거해
원본 배열을 직접 변경
하고 제거한 요소를 배열로 반환한다.- splice 메서드는 3개의 매개변수가 있다.
1)start
: 원본 배열의요소를 제거하기 시작할 인덱스
로 start만 지정하면 원본 배열의 모든 요소를 제거하고 음수인 경우 배열의 끝에서의 인덱스를 의미한다.
2)deleteCount(옵션)
: 원본 배열의 요소를 제거하기 시작할 인덱스인start부터 제거할 요소의 개수
로 0인 경우 아무런 요소도 제거되지 않는다.
3)items(옵션)
:제거한 위치에 삽입할 요소의 목록
으로 생략할 경우 원본 배열에서 요소들을 제거하기만 한다.
- splice 메서드에 3개의 인수 모두 전달하면
-첫 번째 인수, 1)시작 인덱스
부터
-두 번째 인수, 2)제거할 요소의 개수
만큼 원본 배열에서 제거 후
-셋 번째 인수, 3)제거한 위치에서 삽입할 요소
들을 원본 배열에 삽입한다.
<script> const arr = [1, 2, 3, 4] // 원본 배열의 인덱스 1부터, 2개의 요소 삭제 후, 그 자리에 새로운 요소 20, 30 삽입한다. const result = arr.splice(1, 2, 20, 30) // 제거한 요소가 배열로 반환 console.log(result); // 2, 3 // splice 메소드 역시 원본 배열을 직접 변경 console.log(arr); // [1, 2, 20, 30 ] </script>
- splice 메서드의 첫 번째 인수가 음수면 원본 배열에 배열 끝에서부터 요소가 삭제되고 삭제된 요소를 복사하여 배열로 반환한다.
<script> const arr = [1, 2, 3] // 배열의 끝에서부터 요소를 두 개 복사하여 반환한다 arr.splice(-2) // [2, 3] console.log(arr) // [1] </script>
- splice 메서드의 두 번째 인수, 제거할 요수 개수를 0으로 지정하면 원본 배열에 새로운 요소들만 삽입하고 빈 배열을 반환한다.
<script> const arr = [1, 2, 3, 4] // 원본 배열의 인덱스 1부터, 0개의 요소 삭제 후, 그 자리에 새로운 요소 100 삽입 const result = arr.splice(1, 0, 100) // 제거한 요소가 배열로 반환 console.log(result); // [] // splice 메소드 역시 원본 배열을 직접 변경 console.log(arr); // [1, 100, 2, 3, 4 ] </script>
- splice 메서드의 세 번째 인수, 제거한 위치에 추가할 요소의 목록을 전달하지 않으면 원본 배열에서 지정된 요소를 삭제하고 삭제된 요소를 반환한다.
<script> const arr = [1, 2, 3, 4] // 원본 배열의 인덱스 1부터, 2개의 요소 삭제 const result = arr.splice(1, 2) // 제거한 요소가 배열로 반환 console.log(result); // [2, 3] // splice 메소드 역시 원본 배열을 직접 변경 console.log(arr); // [1, 4 ] </script>
- splice 메서드의 두 번째 인수, 제거한 요소의 개수를 생략하면 첫 번째 인수로 전달된 시작 인덱스부터 원본 배열에 모든 요소를 제거하고 제거한 요소를 반환한다.
<script> const arr = [1, 2, 3, 4] // 원본 배열의 인덱스 1부터, 2개의 요소 삭제 const result = arr.splice(1) // 제거한 요소가 배열로 반환 console.log(result); // [2, 3, 4] // splice 메소드 역시 원본 배열을 직접 변경 console.log(arr); // [1] </script>
QUIZ) 배열에서 특정 요소를 제거하려면 어떻게 할까?🤷
🙆♂️ A1: indexOf 메서드를 통해 특정 요소의 인덱스를 취득한 다음 splice 메서드를 사용해 제거한다.
<script> const arr = [1, 2, 3, 1, 2] // 배열 array에서 item 요소를 제거한다. item 요소가 여러개 존재하면 첫번째 요소만 제거한다. function remove(array, item){ //제거할 item 요소의 인덱스를 취득한다. const index = array.indexOf(item) // 제거할 item 요소가 있다면 제거한다. if(index !== -1) array.splice(index, 1) return array; } console.log(remove(arr, 4)) // [1, 2, 3, 1, 2] console.log(remove(arr, 2)) // [1, 3, 1, 2] console.log(remove(arr, 3)) // [1, 1, 2] </script>
🙆♂️ A2: filter 메서드를 사용해 특정 요소를 제거할 수 있지만 특정요소가 중복된 경우 모두 제거한다.
<script> const arr = [1, 2, 3, 1, 2] // 배열 array에서 모든 item 요소를 제거한다. function removeAll(array, item){ return array.filter(value => value !== item); } console.log(removeAll(arr, 2)) // [1, 3, 1] </script>
- slice 메서드는 인수로 전달된 범위의 요소들을 복사하여 배열로 반환하고
원본 배열은 변경하지 않는다.
- slice 메서드는 두개의 매개 변수를 갖는다.
1)star
: 복사를 시작할 인덱스다. 음수인 경우 배열의 끝에서 인덱스를 나타낸다.
2)end
: 복사를 종료할 인덱스다. 이 인덱스에 해당하는 요소는 복사되지 않고 end는 생략 가능하며 생략 시 기본 값은 length 프로퍼티 값이다.
<script> const arr = [1, 2, 3] // arr[0]부터 arr[1] 직전까지 복사하여 반환 arr.slice(0, 1) // [1] // arr[1]부터 arr[2] 직전까지 복사하여 반환 arr.slice(1, 2) // [2] // 원본은 변경되지 않음 console.log(arr); // [1, 2, 3] </script>
- slice 메서드는 1) 첫 번째 인수(
start
)로 전달 받은 인덱스부터 2) 두 번째 인수(end
)로 전달 받은 인덱스 직전까지 요소들을 복사해 배열로 반환한다.
- slice 메서드의 두 번째 인수를 생략하면 첫 번째 인수로 전달받은 인덱스부터 모든 요소를 복사하여 배열로 반환한다.
<script> const arr = [1, 2, 3] // arr[1] 부터 이후의 모든 요소를 복사하여 반환 arr.slice(1) // [2, 3] </script>
- slice 메서드의 첫 번째 인수가 음수인 경우 배열의 끝에서 부터 요소를 복사하여 배열로 반환한다.
<script> const arr = [1, 2, 3] // 배열의 끝에서 부터 모든 요소를 한개 복사하여 반환 arr.slice(-1) // [3] // 배열의 끝에서부터 모든 요소를 두개 복사하여 반환 arr.slice(-2) // [2, 3] </script>
- slice 메서드의 인수를 모두 생략하면 원본 배열의 복사본을 생성하여 반환한다.
<script> const arr = [1, 2, 3] // 인수를 모두 생략하면 원본 배열의 복사본 생성 후 반환 const copy = arr.slice() console.log(copy); // [1, 2, 3] console.log(copy === arr); // false, 얕은 복사 </script>
- 이때 생성된 복사본은 얕은 복사를 통해 생성된다.
- join 메소드는
원본 배열은 유지
한 채 원본 배열의 모든 요소를 문자열로 변환한 후 인수로 전달받은 문자열 구분자로 연결한 문자열을 반환하는데 이때 구분자는 생략가능하며 기본 구분자는 콤마이다.<script> const arr = [1, 2, 3, 4] //기본 구분자는 콤마 // 원본 배열 arr의 모든 요소를 문자열로 변환 후 기본 구분자로 연결한 문자열 반환 arr.join() // "1,2,3,4" // 원본 배열 arr의 모든 요소를 문자열로 변환 후 빈 문자열 연결한 문자열 반환 arr.join('') // "1234" // 원본 배열 arr의 모든 요소를 문자열로 변환 후 ':' 구분자로 연결한 문자열 반환 arr.join(':') // "1:2:3:4" </script>
- reverse 메서드는 원본 배열의 순서를 반대로 뒤집어
원본 배열을 변경
하고 반환값 역시 변경된 배열이다.<script> const arr = [1, 2, 3, 4] const result = arr.reverse(); // reverse 메서드는 원본 배열을 직접 변경 console.log(arr); // [3, 2, 1] // 반환 값은 변경된 배열 console.log(result); // [3, 2, 1] </script>
- fill 메서드는 인수로 전달 받은 값을 배열의 처음부터 끝까지 요소로 채우며
원본 배열을 변경
한다<script> const arr = [1, 2, 3]; // 인수로 전달 받은 값 0을 배열의 처음부터 끝까지 요소로 채운다. arr.fill(0); // fill 메서드는 원본 배열을 직접 변경 console.log(arr); // [0, 0, 0] </script>
- 두 번째 인수로 '요소 채우기를 시작할 인덱스'를 전달할 수 있다.
<script> const arr = [1, 2, 3]; // 인수로 전달 받은 값 0을 인덱스 1부터 끝까지 요소로 채운다. arr.fill(0, 1); // fill 메서드는 원본 배열을 직접 변경 console.log(arr); // [1, 0, 0] </script>
- 세 번째 인수로 '요소 채우기를 멈출 인덱스'를 전달할 수 있다.
<script> const arr = [1, 2, 3, 4, 5 ]; // 인수로 전달 받은 값 0을 인덱스 1부터 3 이전까지 요소로 채운다. arr.fill(0, 1, 3); // fill 메서드는 원본 배열을 직접 변경 console.log(arr); // [1, 0, 0, 4, 5] </script>
- fill 메서드를 사용하면 배열을 생성하면서 특정 값으로 요소를 채울 수 있다.
- fill 메소드로 요소를 채울 경우 모든 요소를 하나의 값으로 만으로 채울 수 밖에 없지만 🤷?
<script> const arr = new Array(3) console.log(arr); // [empty * 3] const result = arr.fill(1); console.log(arr); // [1, 1, 1] console.log(result); // [1, 1, 1] </script>
- 🙆♂️Array.from 메서드를 사용하면 두 번째 인수로 전달한 콜백 함수를 통해 요소값을 만들면서 배열을 채울 수 있다.
- Array.from 메서드는 두번째 인수로 전달한 콜백함수에 첫 번째 인수에 의해 생성된 배열의 요소값과 인덱스를 순차적으로 전달하고 콜백함수의 반환값으로 구성된 배열을 반환한다.
<script> // 인수로 전달받은 정수만틈 요소를 생성하고 0부터 1식 증가하면서 요소를 채운다. const squences = (length = 0) => Array.from({ length } ,(_, i) => i); // const squences = (length = 0) => Array.from(new Array(length), (_, i) => i); console.log(squences(3)); // [0, 1, 2] </script>
- includes 메소드는 배열 내에 특정 요소가 포함되어 있는지 확인하여 true 또는 false를 반환한다.
- 첫 번째 인수로 검색할 대상을 지정한다.
<script> // 인수로 전달받은 정수만틈 요소를 생성하고 0부터 1식 증가하면서 요소를 채운다. const arr = [1, 2, 3]; arr.includes(2); true arr.includes(100); false </script>
- 두 번째 인수로 검색을 시작할 인덱스를 전달할 수 있고 생략시 기본 값이 0이 설정되고 인수에 음수를 전달하면 length 프로퍼티 값과 음수 인덱스를 합산하여 검색 시작 인덱스를 전달한다.
<script> // 인수로 전달받은 정수만틈 요소를 생성하고 0부터 1식 증가하면서 요소를 채운다. const arr = [1, 2, 3]; arr.includes(1, 1); false arr.includes(3, -1); true </script>
- 배열에서 인수로 전달된 요소를 검색하여 인덱스로 반환하는 indexOf 메서드를 사용해도 배열 내에 특정 요소가 포함되어있는지 확인 할 수 있다
- 하지만 indexOf 메서드를 사용하면 반환 값이 -1인지 꼭 확인해보아야 하는게 배열에 NaN이 포함되어있는 확인할 수 없는 문제가 있기 때문이다.
<script> [NaN].indexOf(NaN) !== -1; // false [NaN].indexOf(NaN) // ture </script>
- flat 메서드는 인수로 전달한 깊이만큼 재귀적으로 배열을 평탄화한다.
<script> [1, [2, 3, 4, 5]].flat() // [1,2,3,4,5] </script>
- 중첩 배열을 평탄화할 깊이를 인수로 전달할 수 고 생략시 기본값은 1이며 infinity를 전달하면 중첩배열 모두 평탄화한다.
<script> [1, [2, [3, [4]]].flat() // [1,2,[3,[4]]] [1, [2, [3, [4]]].flat(1) // [1,2,[3,[4]] [1, [2, [3, [4]]].flat(2) // [1, 2, 3, [4]] [1, [2, [3, [4]]].flat().flat // [1, 2, 3, [4]] [1, [2, [3, [4]]].flat(infinity) // [1, 2, 3, 4] </script>
- 배열의 많은 메서드들을 결과물을 반환하는 패턴으로 나누어서 정리하자
1>원본 배열을 변경하는 메서드와 2>변경하지 않고 새로운 배열을 생성해 반환하는 메서드
- 책 모던 자바스크립트 딥 다이브 - 503p ~ 507p