Logo

자바스크립트 배열의 slice()와 splice() 함수

자바스크립트에서 배열을 다룰 때 자주 사용하게되는 함수 중에서 이름이 상당히 비슷한 slice()splice()가 있습니다. 이번 포스팅에서는 예제 코드를 작성하면서 이 두 함수가 어떤 점이 비슷하고 어떤 점이 다른지에 대해서 알아보겠습니다.

slice() 함수

slice() 함수는 배열로 부터 특정 범위를 복사한 값들을 담고 있는 새로운 배열을 만드는데 사용합니다. 첫번째 인자로 시작 인덱스(index), 두번째 인자로 종료 인덱스를 받으며, 시작 인덱스부터 종료 인덱스까지 값을 복사하여 반환합니다.

간단한 실습을 위해 숫자 0부터 19까지를 담고있는 배열을 생성하여 nums라는 변수에 할당해보겠습니다. (브라우저의 콘솔에서 따라서 코딩해보시기를 추천드립니다.)

> nums = Array(20).fill().map((_, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

이 숫자 배열에서 5부터 9까지를 복사한 값을 담고 있는 새로운 배열을 만들어 보겠습니다.

> nums.slice(5, 10)
< [5, 6, 7, 8, 9]

여기서 주의할 점은 첫번째 인자로 넘어온 시작 인덱스가 가리키는 값은 포함하지만, 두번째 인자로 넘어온 종료 인덱스가 가리키는 값은 포함하지 않는다는 것입니다.

두번째 인자를 넘기지 않으면, 시작 인덱스가 가리키는 값부터 배열의 마지막 값까지 모두 복사해줍니다.

> nums.slice(10)
< [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

첫번째 인자도 넘기지 않으면, 배열의 처음 값부터 마지막 값까지 전체를 복제해버리는 효과를 낼 수 있습니다.

> nums.slice()
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

slice() 함수는 밑에서 다룰 splice() 함수와 달리 아무리 많이 호출해도 원본 배열의 값은 절대 건드리지 않습니다. 따라서 원본 배열이 그대로 보존되야 하는 상황에서 매우 유용하게 사용됩니다.

> nums
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

splice() 함수

slice() 함수의 이름에서 알파벳 p가 하나 더 있는 splice() 함수는 다목적으로 사용할 수 있는 함수인데요. 이 함수로는 배열로 부터 특정 범위를 삭제하거나 새로운 값을 추가 또는 기존 값을 대체할 수 있습니다. 첫번째 인자로 시작 인덱스(index), 두번째 인자로 몇개의 값을 삭제할지, 그리고 세번째 인자부터는 추가할 값을 가변 인자로 넘길 수 있으며, 삭제된 값을 담고 있는 배열을 반환합니다.

역시 위와 동일한 방법으로 nums라는 숫자 배열을 생성해놓고 실습을 시작하겠습니다.

> nums = Array(20).fill().map((_, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

이 숫자 배열에서 인덱스 5가 가리키는 값부터 3개의 값을 삭제해보겠습니다.

> nums.splice(5, 3)
< [5, 6, 7]
> nums
< [0, 1, 2, 3, 4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

삭제된 3개의 값을 담고 있는 배열이 반환되며, 원본 배열로 부터 3개의 값이 빠져나간 것을 알 수 있습니다.

이번에는 인덱스 5가 가리키는 값부터 아무 값도 삭제하지 않고, -5, -6, -7을 추가해보겠습니다.

> nums.splice(5, 0, -5, -6, -7)
< []
> nums
< [0, 1, 2, 3, 4, -5, -6, -7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

삭제된 값이 없으므로 빈 배열이 반환되고, 이전에 값이 삭제된 자리에 -5, -6, -7을 들어간 것을 알 수 있습니다.

이번에는 인덱스 10이 가리키는 값부터 2개의 값을 -10, -11로 대체해보겠습니다.

> nums.splice(10, 2, -10, -11)
< [10, 11]
> nums
< [0, 1, 2, 3, 4, -5, -6, -7, 8, 9, -10, -11, 12, 13, 14, 15, 16, 17, 18, 19]

삭제된 2개의 값을 담고 있는 배열이 반환되며, 원본 배열의 10, 11이 있던 자리에 -10, -11에 들어가 앉아있는 것을 볼 수 있습니다.

splice() 함수에 첫번째 인자만 넘기면 해당 인덱스가 가리키는 값을 포함해서 배열의 마지막 값까지 삭제가 됩니다.

> nums.splice(15)
< [15, 16, 17, 18, 19]
> nums
< [0, 1, 2, 3, 4, -5, -6, -7, 8, 9, -10, -11, 12, 13, 14]

splice() 함수 첫 번째 인자로 0을 넘기면 배열에 있는 모든 원소를 삭제되겠죠?

> nums.splice(0)
< [0, 1, 2, 3, 4, -5, -6, -7, 8, 9, -10, -11, 12, 13, 14]
> nums
< []

splice() 함수를 사용할 때 가장 주의할 부분은 삭제된 값을 담고 있는 새로운 배열이 반환될 뿐만 아니라 원본 배열에도 변경이 가해진다는 점입니다. 따라서 의도치 않은 데이터 유실이나 변경으로 이어질 수 있으니 특히 데이터의 불변성(immutability)이 보장되어야 하는 프로그램을 작성할 때 주의하셔야 합니다.

slice() vs. splice()

많은 자바스크립트 개발자들이 slice() 함수와 splice() 함수를 햇갈려하는 이유는 비단 이름이 비슷해서 뿐만 아니라 실제로 동일한 목적을 위해서 두 함수 중에 아무거나 사용해도 무방한 경우가 있기 때문입니다.

예를 들어, nums 배열에서 5부터 7까지를 복사한 값을 담고 있는 새로운 배열을 얻고 싶을 때 다음 두 가지 방법을 다 쓸 수가 있습니다.

> nums = Array(20).fill().map((_, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
> nums.slice(5, 8)
< [5, 6, 7]
> nums.splice(5, 3)
< [5, 6, 7]

차이점이라고 하면 두번째 인자로 slice() 함수는 종료 인덱스, splice() 함수는 몇개의 값을 때어낼지를 넘긴다는 것 뿐인데요.

하지만 이 두 함수를 동일한 배열을 대상으로 여러 번 호출할 수 있는 상황이라면 얘기가 좀 틀려집니다.

> nums = Array(20).fill().map((_, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
> nums.slice(5, 8) // slice() 1회 호출
< [5, 6, 7]
> nums.slice(5, 8) // slice() 2회 호출
< [5, 6, 7]
> nums.slice(5, 8) // slice() 3회 호출
< [5, 6, 7]
> nums.slice(5, 3) // splice() 1회 호출
< [5, 6, 7]
> nums.splice(5, 3) // splice() 2회 호출
< [8, 9, 10]
> nums.splice(5, 3) // splice() 3회 호출
< [11, 12, 13]

항상 같은 배열을 반환한는 slice() 함수와 달리 splice() 함수는 계속해서 원본 배열를 깍아 먹기 때문에 동일한 인자로 여러 번 함수를 호출했을 때 매번 다른 배열이 반환되게 됩니다.

마치면서

지금까지 미묘하게 비슷하면서도 다른 slice() 함수와 splice() 함수에 대해서 비교해보았습니다. 이 두 함수는 자바스크립트에서 배열을 다룰 때 많이 사용되는 함수이므로 본 포스팅이 두 함수의 공통점과 차이점에 대해서 정리할 수 있는 기회가 되었으면 좋겠습니다.