자바스크립트 기본3(배열의 내장함수2)

황에녹·2023년 6월 13일
0

기초 학습

목록 보기
3/3

splice

배열에서 특정 항목을 제거할 때 사용함.

배열을 만들어보겠습니다.

const numberArray = [1, 2, 3, 4, 5];

이 배열에서 특정항목(4)을 제거하고 싶습니다.

내장함수 indexOf를 활용해서 특정항목(4)의 인덱스를 찾을 수 있고,
splcie를 통해서 특정항목을 제거할 수 있습니다.

const numberArray = [1, 2, 3, 4, 5];
const index = numberArray.indexOf(4); // 3

numberArray.splice(index, 1);

console.log(numberArray); // [1, 2, 3, 5];

splice 함수의 첫 번째 인자'몇 번째 인덱스부터 지울 것인지',
두 번째 인자는 '해당 인덱스부터 몇 개까지 지울 것인지'를 의미합니다.

다음과 같이 두 번째 인자에 1 이외의 값을 넣어
더 제거할 수 있습니다.

const numberArray = [10, 20, 30, 40, 50];
const index = numberArray.indexOf(10); // 0

numberArray.splice(index, 3); //0번째 인덱스부터 3개의 원소 제거

console.log(numberArray); // [40, 50];

중요한 것은,
splice는 새로운 배열을 반환하는 것이 아니라,
원본을 직접 수정합니다.
따라서 원본에 영향을 주지 않고 새로운 배열을 사용하려면
아래의 slice 함수를 사용해야합니다.

slice

slice는 splice와 비슷하게 배열을 잘라낼 때 사용합니다.
하지만 기존의 배열은 건들이지 않습니다.

slice의 첫 번째 인자는 '몇 번째 인덱스부터 자를 것인지',
두 번째 인자는 '몇 번째 인덱스 앞까지 자를 것인지'를 의미합니다.

const numbers = [1, 2, 3, 4, 5];
const sliceNumbers = numbers.slice(0, 2); //0번째 인덱스부터 2번째 인덱스 앞까지

console.log(sliceNumbers); // [1, 2]

slice 함수는 다음과 같이 활용하여
원본과 똑같은 배열을 복사할 수 있습니다.

const numbers = [1, 2, 3, 4, 5];
const numbersLength = numbers.length; // 5

const copyNumbers = numbers.slice(0, numbersLength);

console.log(copyNumbers); // [1, 2, 3, 4, 5];

그런데 아래의 코드로도 똑같은 배열을 만들어 낼 수 있는데,
굳이 slice 함수를 사용해서 복사해야만 하는 이유는 무엇일까요?

const numbers = [1, 2, 3, 4, 5];
const copyNumbers = numbers;

console.log(copyNumbers); // [1, 2, 3, 4, 5];

slice의 활용(얕은복사와 깊은복사)

먼저 두 배열의 차이를 보겠습니다.
1.원본 배열을 새로운 변수에 할당한 경우

const numbers = [1, 2, 3, 4, 5];
const copyNumbers = numbers;

numbers === copyNumbers; // true

copyNumbers.splice(0, 1); 

console.log(copyNumbers); // [2, 3, 4, 5];
console.log(numbers); // [2, 3, 4, 5];

2.slice 함수로 새로운 배열을 만든 경우

const numbers = [1, 2, 3, 4, 5];
const copyNumbers = numbers.slice(0, numbers.length);

numbers === copyNumbers; // false

copyNumbers.splice(0, 1); 

console.log(copyNumbers); // [2, 3, 4, 5];
console.log(numbers); // [1, 2, 3, 4, 5];

얕은 복사

우선 배열의 데이터 타입은 '객체 타입'입니다.
따라서 1번의 경우
새로운 변수(copyNumbers)에 원본 배열을 할당했고,
'copyNumbers'에는 '원본 배열의 값'이 아닌 '원본 배열의 값이 담긴 주소'가 할당되었습니다.
즉, 값이 담긴 같은 주소를 서로 공유하고 있는 상태입니다.

따라서, 'copyNumbers'를 수정하게 되면
주소가 바라보는 값이 수정되는 것이고,
같은 주소를 갖고 있는 원본 배열 numbers도 함께 수정이 되는 것입니다.
반대의 경우도 마찬가지구요.(numbers 수정시, copyNumbers도 함께 수정됨)

이것을 '얕은 복사'라고 합니다.

깊은 복사

2번의 경우는 다릅니다.

slice 함수를 통해서 주소가 다른 새로운 배열을 만들었습니다.
따라서 원본 배열과 'copyNumbers'를 비교했을 때 값이
'false'가 나오고,
'copyNumbers'를 수정해도 원본 배열에 영향이 없습니다.

객체타입의 데이터(배열, 객체, 함수 등)를
꼭 slie를 통해서만 깊은 복사를 할 수 있는 것은 아닙니다.
후에 나오는 concat, Object.assign, ES6문법인 Spread 등을 통해서도
깊은 복사를 할 수 있습니다.

얕은 복사와 깊은 복사를 알아야 하는 이유

  • 얕은 복사로 객체 타입 데이터를 복사한다면,
    복사된 데이터를 수정할 경우, 원본도 함께 수정됩니다.
    따라서 의도치 않는 변화가 일어날 수 있습니다.

  • 리액트는 원본 데이터와 변경 데이터를 비교 후,
    변경된 사항이 있을 때에 변경 데이터를 화면에 보여줍니다.
    (원활한 작업수행을 위해서는 해당 개념을 숙지해야합니다).

추가로 완전한 깊은 복사도 있습니다.
2차원 배열/객체는 위 방법으로 완전하게 복사할 수 없는데요.
완전한 깊은 복사에 대해서는 다른 곳에서 자세히 설명하겠습니다.

다음은 2차원 배열/객체가 완전히 복사되지 않는 예시입니다.

const numbers = [1, 2, 3, [4, 5]];
const copyNumbers = numbers.slice(0, numbers.length);

numbers === copyNumbers; // false
numbers[3] === copyNumbers[3]; // true

/* 배열 속 배열의 주소는 서로 공유하고 있는 상태.*/

shift/pop

shift는 배열의 맨 앞 원소를 추출,
pop은 배열의 맨 뒤 원소를 추출합니다.

const numbers = [1, 2, 3];

numbers.pop(); // 맨 뒤 제거

console.log(numbers); // [1, 2]

numbers.shift(); // 맨 앞 제거

console.log(numbers); // [2]

unshift/push

unshift는 배열의 맨 앞에 원소를 추가,
push는 배열의 맨 뒤에 원소를 추가합니다.

const numbers = [1, 2, 3];

numbers.push(4); // 맨 뒤 추가

console.log(numbers); // [1, 2, 3, 4]

numbers.unshift(0); // 맨 앞 추가

console.log(numbers); // [0, 1, 2, 3, 4]

concat

concat은 배열들을 서로 합칠 수 있고,
새로운 배열을 만들어냅니다.

const firstNumbers = [1, 2, 3];
const secondNumbers = [4, 5, 6];

const concatNumbers1 = firstNumbers.concat(secondNumbers);
console.log (concatNumbers1); // [1, 2, 3, 4, 5, 6];

const concatNumbers2 = secondNumbers.concat(firstNumbers);
console.log (concatNumbers2); // [4, 5, 6, 1, 2, 3];

console.log(concatNumbers2.concat(concatNumbers2)); // [4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3]

join

join은 배열의 값들을 문자열 형태로 합쳐줍니다.

const numbers = [1, 2, 3, 4, 5];

console.log(numbers.join()); // 1,2,3,4,5
console.log(numbers.join( )); // 1,2,3,4,5
console.log(numbers.join('')); // 12345
console.log(numbers.join(' ')); // 1 2 3 4 5
console.log(numbers.join('-')); // 1-2-3-4-5
console.log(numbers.join(',')); // 1,2,3,4,5
console.log(numbers.join(', ')); // 1, 2, 3, 4, 5

reduce

reduce는 2개의 인자를 갖는 함수입니다.
2개의 인자를 통해 배열의 총합을 구할 수 있고,
그 외에도 다양하게 활용이 가능한 함수입니다.

reduce함수를 활용하여 'numbers'배열의 총합을 구해보겠습니다.

const numbers = [15, 40, 260, 1, 9];

const result = numbers.reduce((accumulator, current)=> accumulator + current, 0);

console.log(result); // 325

reduce함수의 첫 번째 인자(accumulator, current)는 콜백함수입니다.
'accumulator'는 누적되는 값을 의미하고,
'current'는 현재 오는 값을 의미합니다.

두 번째 인자(0)는 초기 값을 의미합니다.

이것을 바탕을 위 함수가 어떻게 실행되었는지 알아보겠습니다.

  1. 초기값은 0으로 설정했습니다. 따라서 콜백함수의 첫 번째 인자(accumulator)는
    0부터 시작하고, 두 번째 인자(current)는 'numbers'의 0번째 인덱스 값인 15가 됩니다.

accumulator와 current를 합칩니다.

0 + 15 // 15
  1. 현재 누적된 값은 15입니다.
    따라서 'accumulator'는 15가 되고,
    그 다음으로 오는 값인 'current'는 'numbers'의 1번째 인덱스 값인 40이 됩니다.

accumulator와 current를 합칩니다.

15 + 40 // 55
  1. 현재 누적된 값은 55입니다.
    따라서 'accumulator'는 55가 되고,
    다음으로 오는'current'값과 합칩니다.
    'numbers'가 갖고 있는 원소들을 모두 합칠 때까지 함수가 반복 진행됩니다.
55 + 260 // 315

315 + 1 // 316

316 + 9 // 325
profile
개발, 영화, 음악

0개의 댓글