배열에는 원본 배열(배열 메서드를 호출한 배열, 즉 배열 메서드의 구현체 내부에서 this
가 가리키는 객체)을 직접 변경하는 메서드와,
원본 배열을 직접 변경하지 않고 새로운 배열을 생성하여 반환하는 메서드가 있다.
가급적 원본 배열을 직접 변경하지 않는 메서드를 사용하는 편이 좋다.
Array.isArray
메서드는 전달된 인수가 배열이면 true, 배열이 아니면 false 를 반환한다.
Array.isArray 는 Array 생성자 함수의 정적 메서드다.
-> 정적 메서드는 인스턴스를 생성하지 않아도 참조/호출 할 수 있는 메서드를 말한다!
indexOf
메서드는 원본 배열에서 인수로 전달된 요소를 검색하여 인덱스를 반환한다.
- 원본 배열에 인수로 전달한 요소와 중복되는 요소가 여러개 있다면
--> 첫 번째로 검색된 요소의 인덱스를 반환한다!!- 원본 배열에 인수로 전달한 요소가 존재하지 않으면 -1을 반환한다.
indexOf
의 두 번째 인수는 검색을 시작할 인덱스다.
두 번째 인수를 생략하면 처음부터 검색한다!
let arr = [1, 2, 2, 3];
// 두 번째 인수는 검색을 시작할 인덱스다.
arr.indexOf(2, 2); // 2
indexOf
메서드는 배열에 특정 요소가 존재하는지 확인할 때 유용하나,
이러한 용도로 존재하는 메서드는 아니다!
--> indexOf
메서드 대신 Array.prototype.includes
메서드를 사용하면 가독성이 더 좋다!!! (도움님 왈..)
인수로 입력한 값이 배열에 존재하면 --> true
존재하지 않는다면 --> false 를 반환한다.
Array.prototype.includes
의 두 번째 인수는 검색을 시작할 인덱스다.
두 번째 인수를 생략하면 처음부터 검색한다!
// Array.prototype.includes 메서드를 사용해 특정 요소가 존재하는지 확인해보자!
const foods = ["apple", "banana", "orange"];
// foods 배열에 'orange' 요소가 존재하는지 확인한다.
// 'orange' 요소가 존재하므로 if 문은 실행되지 않는다.
if (!foods.includes("orange")) {
// 배열에 'orange' 요소가 존재하지 않으면 'orange' 요소를 추가한다.
foods.push("orange");
}
console.log(foods); // ["apple", "banana", "orange"]
push
메서드는 인수로 전달받은 모든 값을 원본 배열의 마지막 요소로 추가하고,
변경된length
프로퍼티 값을 반환한다.
push
메서드는 원본 배열을 직접! 변경한다.
push
메서드는 원본 배열을 직접 변경하는 부수 효과가 있다.
따라서 push
메서드보다는 스프레드 문법을 사용하는 편이 좋다!
--> 스프레드 문법을 사용하면 함수 호출 없이 표현식으로 마지막에 요소를 추가할 수 있으며,
원본 배열을 직접 변경하는 부수 효과도 없다!
const arr = [1, 2];
// ES6 스프레드 문법 -> 얕은 복사
// 얕은 복사시 타입을 바꾸는 것은 바람직하지 않다!
const newArr = [...arr, 3];
console.log(newArr); // [1, 2, 3];
pop
메서드는 원본 배열에서 마지막 요소를 제거하고 제거한 요소를 반환한다.
원본 배열이 빈 배열이라면undefined
를 반환한다.
pop
메서드는 원본 배열을 직접 변경한다!
unshift
메서드는 인수로 전달받은 모든 값을 원본 배열의 선두에 요소로 추가하고,
변경된length
값을 반환한다.
unshift
메서드는 원본 배열을 직접 변경한다!
unshift
메서드는 원본 배열을 직접 변경하는 부수 효과가 있다.
따라서 push 메서드보다는 스프레드 문법을 사용하는 편이 좋다!
const arr = [1, 2];
// // ES6 스프레드 문법 -> 얕은 복사
// unshift 메서드 대신 배열의 선두에 스프레드 문법으로 요소를 추가하여
// 새로운 배열 생성
const newArr = [3, ...arr];
console.log(newArr);
shift
메서드는 원본 배열에서 첫 번째 요소를 제거하고 제거한 요소를 반환한다.
원본 배열이 빈 배열이면undefined
를 반환한다.
shift
메서드는 원본 배열을 직접 변경한다!
concat
메서드는 인수로 전달된 값들(배열 또는 원시값)을
원본 배열의 마지막 요소로 추가한 새로운 배열을 반환한다.
인수로 전달한 값이 배열인 경우 배열을 해체하여
--> 새로운 배열의 요소로 추가한다!!
shift
메서드는 원본 배열은 변경되지 않는다!
push
와 unshift
메서드는 concat
메서드로 대체할 수 있다.
-> push
와 unshift
메서드를 사용할 경우 원본 배열을 반드시 변수에 저장해 두어야 한다! (원본 배열을 직접 변경하기 때문에!)
-> concat
메서드를 사용할 경우 반드시 반환값을 변수에 할당받아야 한다. (새로운 배열을 리턴하기 때문에!)
인수로 전달받은 값이 배열인 경우,
push
와 unshift
메서드는 배열을 그대로 원본 배열의 마지막 / 첫 번째 요소로 추가한다.
concat
메서드는 인수로 전달받은 배열을 해체하여 새로운 배열의 마지막 요소로 추가한다.
concat 메서드는 ES6의 스프레드 문법으로 대체할 수 있다!
const result = [...[1, 2], ...[3, 4]];
console.log(result); // [1, 2, 3, 4]
결론적으로 push
/ unshift
메서드와 concat
메서드를 사용하는 대신
--> ES6 의 스프레드 문법을 일관성 있게 사용하는 것을 권장한다!
원본 배열의 중간에 요소를 추가하거나 중간에 있는 요소를 제거하는 경우
splice
메서드를 사용한다.
splice
메서드는 3개의 매개변수가 있으며
원본 배열을 직접 변경한다.
제거한 요소가 배열로 반환된다!
💡splice 메서드의 매개 변수
3.세번째 매개변수 (items)
배열에서 특정 요소를 제거하려면
--> indexOf
메서드를 통해 특정 요소의 인덱스를 취득한 다음 splice
메서드를 사용한다.
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, 2)); // [1,3,1,2]
// 제거한 요소가 없어 원본 그대로 반환된다.
console.log(remove(arr, 10)); // [1,3,1,2]
filter
메서드를 사용하여 특정 요소를 제거할 수도 있다.
하지만 특정 요소가 중복된 경우 모두 제거된다.
slice
메서드는 인수로 전달된 범위의 요소들을 복사하여 배열로 반환한다.
원본은 변경되지 않는다.
이름이 유사한splice
메서드는 원본 배열을 변경하므로 주의하자~!
💡slice 메서드의 매개 변수
1. 첫 번째 매개변수 (start)
slice
메서드는 첫번째 인수(start)로 전달받은 인덱스부터 두 번째 인수(end) 로 전달받은 인덱스 이전(end 미포함)까지 요소들을 복사하여 배열로 반환한다.
slice
메서드의 두 번째 인수(end)를 생략하면,
첫 번째 인수(start)로 전달받은 인덱스부터 모든 요소를 복사하여 배열로 반환한다.
💡 slice 메서드의 첫 번째 인수가 음수인 경우
-> 배열의 끝에서부터 요소를 복사하여 배열로 반환한다.
const arr = [1, 2, 3];
// 배열의 끝에서부터 요소를 한 개 복사하여 반환한다.
arr.slice(-1); // -> [3]
// 배열의 끝에서부터 요소를 두 개 복사하여 반환한다.
arr.slice(-2); // -> [2, 3]
--> 이 때 생성된 복사본 배열은 얕은 복사를 통해 생성된다!
const todos = [
{ id: 1, content: "HTML", completed: false },
{ id: 2, content: "CSS", completed: true },
{ id: 3, content: "Javascript", completed: false }
];
// 얕은 복사(shallow copy)
const _todos = todos.slice();
// const _todos = [...todos];
// _todos와 todos 는 참조값이 다른 별개의 객체다!
console.log(_todos === todos); // false
// 배열 요소의 참조값은 동일한 것을 확인할 수 있다.
// -> 즉 얕은 복사 되었다는 것을 확인할 수 있다!
console.log(_todos[0] === todos[0]);
💡 얕은 복사와 깊은 복사
객체를 프로퍼티 값으로 갖는 객체의 경우
얕은 복사는
--> 한 단계까지만 복사하는 것을 말하고
깊은 복사는
--> 객체에 중첩되어 있는 객체까지 모두 복사하는 것을 말한다
slice
메서드가 복사본을 생성하는 것을 이용하여
--> argument
, HTMLCllection
, NodeList
같은 유사 배열 객체를 배열로 변환할 수 있다.
(p.524 예제 27-73 참조)
하지만! Array.from
메서드를 사용하면
--> 더욱 간단하게 유사 배열 객체를 배열로 변환할 수 있다!
--> Array.from
메서드는 유사 배열 객체 또는 이터러블 객체를 배열로 변환하는 메서드로 만들어졌기 때문이다!
function sum() {
var arr = Array.from(arguments);
console.log(arr);
}
sum(1, 2, 3); // [1, 2, 3]
arguments 객체는 유사 배열 객체이면서 이터러블 객체이다.
이터러블 객체는 ES6의 스프레드 문법을 사용해서 간단하게 배열로 변환할 수 있다.
function sum() {
// 이터러블을 배열로 변환 (ES6 스프레드 문법)
const arr = [...arguments];
console.log(arr);
}
sum(1,2,3); // [1, 2, 3]
join 메서드는 원본 배열의 모든 요소를 문자열로 변환한 후,
인수로 전달 받은 문자열, 즉 구분자로 연결한 문자열을 반환한다.
구분자는 생략 가능하며, 기본 구분자는 콤마(,)다.
let arr = [1, 2, 3, 4];
console.log(arr.join(""));
console.log(arr.join());
console.log(arr.join(":"));
reverse 메서드는 원본 배열의 순서를 반대로 뒤집는다.
이 때 원본 배열이 변경된다.
반환값은 변경된 배열이다.
ES6에서 도입된 fill 메서드는 인수로 전달받은 값을 배열의 처음부터 끝까지 요소로 채운다.
이 때, 원본 배열이 변경된다.
두 번째 인수로
--> 요소 채우기를 시작할 인덱스를 전달할 수 있다.
세 번째 인수로
--> 요소 채우기를 멈출 인덱스를 전달할 수 있다.
--> 이 때 세 번째 인수로 전달한 인덱스의 이전까지를 첫 번째 인수로 채운다.
fill 메서드로 요소를 채울 경우
--> 모든 요소를 하나의 값만으로 채울 수밖에 없다는 단점이 있다.
하지만! Array.from 메서드는
--> 두 번째 인수로 전달한 콜백 함수에 첫 번째 인수에 의해 생성된 배열의 요소 값과 인덱스 값을 순차적으로 전달하면서 호출하고, 콜백 함수의 반환값으로 구성된 배열을 반환한다.
const sequences = (length = 0) => Array.from({ length }, (_, i) => i);
console.log(sequences(3));
ES7에서 도입된 includes 메서드는 배열 내애 특정 요소가 포함되어 있는지 확인하여
--> true 또는 false 를 반환한다.
첫 번째 인수로 검색할 대상을 지정한다.
두 번째 인수로 검색을 시작할 인덱스를 전달할 수 있다.
두 번째 인덱스를 생략할 경우 기본값 0이 설정된다.
두 번째 인수에 음수를 전달하면
length 프로퍼티 값과 음수 인덱스를 합산(length + index)하여
검색 시작 인덱스를 설정한다.
const arr = [1, 2, 3];
// 배열에 요소 3이 포함되어 있는지 인덱스 2(arr.length -1) 부터 확인한다.
arr.includes(3, -1); // -> true
indexOf 메서드로도 배열 내에 특정 요소가 있는지 확인할 수 있지만,
indexOf 메서드를 사용하면 반환값이 -1 인지 확인해 보아야 하고,
배열에 NaN 이 포함되어 있는지 확인할 수 없다는 문제가 있다.
ES10 에서 도입된 flat 메서드는
인수로 전달한 깊이만큼 재귀적으로 배열을 평탄화 한다.
중첩 배열을 평탄화할 깊이를 인수로 전달할 수 있다.
인수를 생략할 경우 기본값은 1이다.
인수로 infinity 를 전달하면 중첩 배열 모두를 평탄화한다.