
filter()메서드는 주어진 배열의 일부에 대한 얕은 복사본을 생성하고, 주어진 배열에서 제공된 함수에 의해 구현된 테스트를 통과한 요소로만 필터링 한다.
객체의 얕은 복사는 복사본의 속성이 복사본이 만들어진 원본 객체와 같은 참조 (메모리 내의 같은 값을 가리킴)를 공유하는 복사이다.
즉, filter() 메소드는 주어진 콜백 함수가 true를 반환하는 요소들만을 선택하여 새로운 배열을 만든다.
arr.filter(callback(element, index, array), thisArg)
근데 여기서 내가 가장 헷갈렸던 것은 "filter() 메소드는 기존 배열을 변경하지 않는다"는 말이었다.
얕은 복사를 하니까 기존 배열을 변경할텐데 왜 변경을 안한다는 걸까?
예를 들어, 객체들의 배열이 있고 이 배열에 filter 메소드를 사용한다고 가정해보자.
let arr = [{ a: 1 }, { a: 2 }, { a: 3 }];
let filteredArr = arr.filter(obj => obj.a > 1);
여기서 filteredArr은 원래의 arr에서 필터링된 새로운 배열이다. 하지만 이 새로운 배열의 각 객체는 원래의 arr에 있는 객체와 같다. 즉, 같은 메모리 공간에 있는 데이터를 가리키는 것이다.
따라서 만약 이제 filteredArr[0].a = 99;라고 하면, 이것은 filteredArr에 있는 첫 번째 객체의 속성 'a' 값을 변경한다. 그런데 이 객체는 원래의 arr[1]와 동일한 객체이다. 따라서 이 변경사항이 원본 데이터인 arr[1]에도 반영된다. 이게 얕은 복사를 하는 것이다.
그러나 여기서 중요한 점은, 위 예시에서 '기존 배열'란 전체 배열인 arr을 의미하며, '기존 배열이 변경되었다' 또는 '원본 데이터가 수정되었다'라고 해석해서는 안 된다는 것이다. 왜냐하면 filter() 자체적으로 전체 배열을 수정하지는 않고 오직 개개인의 요소({ a: 2 })만이 영향을 받기 때문이다.
reduce나map같은 선언형 배열 메서드는 매우 중요해요!