자바스크립트에서 문자열이나 배열의 일부를 가져오려고 하면 비슷한 이름의 메서드들이 등장합니다.
slice(), splice(), substring(), substr()는 이름은 비슷하지만 사용하는 대상과 인수의 의미가 다릅니다. 특히 두 번째 인수가 끝 위치인지, 개수인지와 원본을 변경하는지를 구분하면 이해하기 쉬워집니다.
1. 먼저 알아둘 기초: 인덱스는 0부터 시작한다
인덱스(index)는 문자열의 문자나 배열 요소가 있는 위치입니다.
const text = "ABCDE";
console.log(text[0]); // "A"
console.log(text[1]); // "B"
console.log(text[4]); // "E"
console.log(text.length); // 5
| 문자 | A | B | C | D | E |
|---|---|---|---|---|---|
| 인덱스 | 0 | 1 | 2 | 3 | 4 |
배열도 같습니다.
const fruits = ["사과", "바나나", "포도"];
console.log(fruits[0]); // "사과"
console.log(fruits[1]); // "바나나"
console.log(fruits.length); // 3
따라서 “인덱스 1부터 가져온다”는 말은 두 번째 위치부터 가져온다는 뜻입니다.
2. 네 가지 메서드 한눈에 비교하기
| 메서드 | 일반적인 사용 대상 | 기본 형태 | 두 번째 인수 | 원본 변경 | 반환값 |
|---|---|---|---|---|---|
slice() |
문자열, 배열 | slice(start, end) |
끝 인덱스, 미포함 | X | 추출한 문자열 또는 새 배열 |
splice() |
배열 | splice(start, deleteCount, ...items) |
삭제할 요소 개수 | O | 삭제된 요소를 담은 배열 |
substring() |
문자열 | substring(start, end) |
끝 인덱스, 미포함 | X | 추출한 문자열 |
substr() |
문자열 | substr(start, length) |
가져올 길이 | X | 추출한 문자열 |
문자열에는 splice()가 없고, 배열에는 substring()과 substr()가 없습니다.
또한 substr()는 레거시 메서드로, 새 코드에서는 slice()나 substring()을 사용하는 편이 좋습니다.
3. slice(): 원본을 유지하면서 일부 가져오기
slice()는 문자열과 배열에서 모두 사용할 수 있습니다. 지정한 구간을 가져오며, 원본을 직접 변경하지 않습니다.
대상.slice(start, end);
start: 가져오기 시작할 인덱스, 포함end: 가져오기를 끝낼 인덱스, 미포함
3-1. 문자열에서 사용하기
const text = "ABCDE";
const result = text.slice(1, 4);
console.log(result); // "BCD"
console.log(text); // "ABCDE"
인덱스 1인 B부터 시작해, 인덱스 4인 E 바로 앞까지 가져옵니다. 따라서 포함되는 인덱스는 1, 2, 3입니다.
끝 인덱스의 문자는 포함하지 않는다는 점을 기억하면 됩니다.
3-2. 끝 인덱스를 생략하면 끝까지 가져온다
const text = "ABCDE";
console.log(text.slice(2)); // "CDE"
console.log(text.slice()); // "ABCDE"
인수를 모두 생략하면 전체 구간을 가져옵니다.
3-3. 음수는 뒤에서부터 위치를 계산한다
const text = "ABCDE";
console.log(text.slice(-1)); // "E"
console.log(text.slice(-2)); // "DE"
console.log(text.slice(0, -1)); // "ABCD"
console.log(text.slice(-4, -1));// "BCD"
문자열 길이가 5라면 -1은 5 - 1 = 4 위치, -2는 5 - 2 = 3 위치를 의미합니다.
slice(0, -1)은 처음부터 마지막 문자 직전까지 가져오므로 마지막 문자를 제외할 때 유용합니다.
3-4. 시작 위치가 끝 위치보다 뒤에 있으면?
const text = "ABCDE";
console.log(text.slice(4, 1)); // ""
console.log(text.slice(2, 2)); // ""
뒤에서 앞으로 읽는 기능은 아닙니다. 계산된 시작 위치가 끝 위치 이상이면 빈 문자열을 반환합니다.
3-5. 배열에서 사용하기
const numbers = [10, 20, 30, 40, 50];
const result = numbers.slice(1, 4);
console.log(result); // [20, 30, 40]
console.log(numbers); // [10, 20, 30, 40, 50]
배열에서도 끝 인덱스는 포함하지 않습니다.
const numbers = [10, 20, 30, 40, 50];
console.log(numbers.slice(2)); // [30, 40, 50]
console.log(numbers.slice(-2)); // [40, 50]
console.log(numbers.slice()); // [10, 20, 30, 40, 50]
3-6. 배열 전체를 복사할 수 있지만, 얕은 복사다
const original = [10, 20, 30];
const copy = original.slice();
copy.push(40);
console.log(original); // [10, 20, 30]
console.log(copy); // [10, 20, 30, 40]
console.log(original === copy); // false
서로 다른 배열이므로 복사본에 요소를 추가해도 원본 배열의 길이는 달라지지 않습니다.
하지만 배열 안에 객체가 있다면 그 객체까지 새로 복사하지는 않습니다.
const original = [{ name: "희라" }];
const copy = original.slice();
console.log(original === copy); // false
console.log(original[0] === copy[0]); // true
copy[0].name = "수정된 이름";
console.log(original[0].name); // "수정된 이름"
배열은 새로 만들어졌지만, 내부 객체는 같은 객체를 가리킵니다. 이것이 얕은 복사(shallow copy)입니다.
4. splice(): 배열을 직접 삭제·추가·교체하기
splice()는 배열의 내용을 직접 변경합니다.
배열.splice(start, deleteCount, item1, item2, ...);
start: 변경을 시작할 인덱스deleteCount: 삭제할 요소 개수item1, item2, ...: 그 위치에 추가할 요소
두 번째 인수는 끝 인덱스가 아니라 삭제할 개수입니다.
4-1. 요소 삭제하기
const fruits = ["사과", "바나나", "포도", "딸기"];
const removed = fruits.splice(1, 2);
console.log(fruits); // ["사과", "딸기"]
console.log(removed); // ["바나나", "포도"]
인덱스 1부터 요소 2개를 삭제합니다. 원본 배열은 바뀌고, 반환값에는 삭제된 요소가 들어갑니다.
4-2. 삭제 없이 요소 추가하기
const fruits = ["사과", "포도"];
const removed = fruits.splice(1, 0, "바나나");
console.log(fruits); // ["사과", "바나나", "포도"]
console.log(removed); // []
삭제할 개수가 0이므로 기존 요소는 삭제하지 않고, 인덱스 1 위치에 바나나를 끼워 넣습니다.
4-3. 요소 교체하기
const fruits = ["사과", "바나나", "포도"];
const removed = fruits.splice(1, 1, "딸기");
console.log(fruits); // ["사과", "딸기", "포도"]
console.log(removed); // ["바나나"]
요소 1개를 삭제하고 그 자리에 새 요소를 추가한 결과입니다. 삭제하는 개수와 추가하는 개수가 같을 필요는 없습니다.
const letters = ["A", "B", "C"];
letters.splice(1, 1, "X", "Y");
console.log(letters); // ["A", "X", "Y", "C"]
4-4. 삭제할 개수를 생략하면 끝까지 삭제한다
const numbers = [10, 20, 30, 40];
const removed = numbers.splice(2);
console.log(numbers); // [10, 20]
console.log(removed); // [30, 40]
단, splice()처럼 인수를 하나도 전달하지 않으면 아무것도 삭제하지 않습니다.
또한 생략과 명시적인 undefined는 다릅니다.
const numbers = [10, 20, 30];
console.log(numbers.splice(1, undefined)); // []
console.log(numbers); // [10, 20, 30]
두 번째 인수에 undefined를 직접 전달하면 삭제할 개수는 0으로 처리됩니다.
4-5. 음수 시작 위치도 사용할 수 있다
const numbers = [10, 20, 30, 40];
const removed = numbers.splice(-2, 1);
console.log(numbers); // [10, 20, 40]
console.log(removed); // [30]
뒤에서 두 번째 위치부터 요소 1개를 삭제한 것입니다.
4-6. const 배열도 splice()로 변경할 수 있다
const numbers = [10, 20, 30];
numbers.splice(1, 1);
console.log(numbers); // [10, 30]
const는 변수에 다른 값을 다시 대입하는 것을 막습니다. 배열 내부의 요소 변경까지 막는 것은 아닙니다.
5. substring(): 두 위치 사이의 문자열 가져오기
substring()은 문자열에서 사용합니다.
문자열.substring(start, end);
일반적인 양수 인덱스에서는 slice()와 결과가 같습니다.
const text = "ABCDE";
console.log(text.substring(1, 4)); // "BCD"
console.log(text.substring(2)); // "CDE"
console.log(text); // "ABCDE"
시작 인덱스는 포함하고, 끝 인덱스는 포함하지 않습니다.
다만 slice()와 다른 규칙이 두 가지 있습니다.
5-1. 음수는 0으로 처리한다
const text = "ABCDE";
console.log(text.slice(-2)); // "DE"
console.log(text.substring(-2)); // "ABCDE"
substring(-2)는 substring(0)처럼 동작합니다.
뒤에서부터 위치를 계산하려면 slice()가 더 편리합니다.
5-2. 시작 인덱스가 더 크면 두 값을 바꿔 처리한다
const text = "ABCDE";
console.log(text.slice(4, 1)); // ""
console.log(text.substring(4, 1)); // "BCD"
console.log(text.substring(1, 4)); // "BCD"
substring(4, 1)은 substring(1, 4)와 같은 결과입니다.
음수 처리와 인덱스 교환 규칙이 함께 적용되는 경우도 있습니다.
const text = "ABCDE";
console.log(text.substring(3, -1)); // "ABC"
먼저 -1을 0으로 처리해 substring(3, 0)이 되고, 두 값을 바꿔 substring(0, 3)처럼 동작합니다.
6. substr(): 시작 위치부터 지정한 길이만큼 가져오기
substr()는 문자열에서 사용하며, 두 번째 인수는 끝 위치가 아니라 가져올 길이입니다.
문자열.substr(start, length);
6-1. 같은 숫자를 전달해도 결과가 다르다
const text = "ABCDE";
console.log(text.slice(1, 3)); // "BC"
console.log(text.substring(1, 3)); // "BC"
console.log(text.substr(1, 3)); // "BCD"
| 코드 | 의미 | 결과 |
|---|---|---|
slice(1, 3) |
인덱스 1부터 3 직전까지 | "BC" |
substring(1, 3) |
인덱스 1부터 3 직전까지 | "BC" |
substr(1, 3) |
인덱스 1부터 3개 | "BCD" |
6-2. 음수 시작 위치와 길이 생략
const text = "ABCDE";
console.log(text.substr(-3, 2)); // "CD"
console.log(text.substr(2)); // "CDE"
console.log(text.substr(1, 0)); // ""
console.log(text.substr(1, -2)); // ""
음수 시작 위치는 뒤에서부터 계산합니다. 길이를 생략하면 끝까지 가져오고, 길이가 0 이하이면 빈 문자열을 반환합니다.
6-3. 새 코드에서는 slice()나 substring() 사용하기
substr()는 오래된 코드와의 호환을 위한 레거시 기능이며, MDN에서는 사용 중단 권고(Deprecated)로 표시합니다.
예를 들어 시작 위치와 길이가 모두 0 이상의 정수라면 다음처럼 바꿀 수 있습니다.
const text = "ABCDE";
const start = 1;
const length = 3;
// 기존 방식
console.log(text.substr(start, length)); // "BCD"
// 대체 방식
console.log(text.slice(start, start + length)); // "BCD"
다만 음수 시작 위치나 음수 길이가 들어올 수 있는 기존 코드라면, 단순히 위 식으로 바꿨을 때 결과가 달라질 수 있으므로 입력 범위를 확인해야 합니다.
7. 가장 헷갈리는 차이점 비교하기
7-1. slice()와 splice(): 추출과 삭제의 차이
아래 예제들은 각각 새 배열로 시작합니다.
const numbers = [10, 20, 30, 40, 50];
const result = numbers.slice(1, 3);
console.log(result); // [20, 30]
console.log(numbers); // [10, 20, 30, 40, 50]
const numbers = [10, 20, 30, 40, 50];
const result = numbers.splice(1, 3);
console.log(result); // [20, 30, 40]
console.log(numbers); // [10, 50]
slice(1, 3)은 인덱스 1부터 3 직전까지 가져오기, splice(1, 3)은 인덱스 1부터 요소 3개 삭제하기입니다.
7-2. 문자열 메서드 결과 비교
아래 표는 text = "ABCDE"를 기준으로 합니다.
| 전달한 인수 | slice | substring | substr |
|---|---|---|---|
(1, 3) |
"BC" |
"BC" |
"BCD" |
(2) |
"CDE" |
"CDE" |
"CDE" |
(-2) |
"DE" |
"ABCDE" |
"DE" |
(4, 1) |
"" |
"BCD" |
"E" |
(1, -1) |
"BCD" |
"A" |
"" |
(2, 2) |
"" |
"" |
"CD" |
7-3. 범위를 벗어나면 어떻게 될까?
const text = "ABCDE";
console.log(text.slice(2, 100)); // "CDE"
console.log(text.substring(2, 100)); // "CDE"
console.log(text.substr(2, 100)); // "CDE"
console.log(text.slice(100)); // ""
console.log(text.substring(100)); // ""
console.log(text.substr(100)); // ""
필요한 구간이 문자열 끝을 넘어가면 존재하는 부분까지만 가져옵니다. 위 예제처럼 시작 위치가 끝보다 뒤에 있으면 가져올 내용이 없어 빈 문자열을 반환합니다.
8. 실제 활용 예제
8-1. 문자열 앞부분 가져오기
const date = "2026-10-12";
console.log(date.slice(0, 4)); // "2026"
8-2. 문자열 마지막 부분 가져오기
const phone = "01012345678";
console.log(phone.slice(-4)); // "5678"
8-3. 배열에서 앞의 세 개만 표시하기
const posts = ["글1", "글2", "글3", "글4", "글5"];
const preview = posts.slice(0, 3);
console.log(preview); // ["글1", "글2", "글3"]
console.log(posts); // ["글1", "글2", "글3", "글4", "글5"]
8-4. 배열 중간에 메뉴 추가하기
const menus = ["홈", "마이페이지"];
menus.splice(1, 0, "상품");
console.log(menus); // ["홈", "상품", "마이페이지"]
8-5. 문자열의 특정 구간 바꾸기
문자열에는 splice()가 없으므로, 앞부분과 뒷부분을 가져와 새로운 문자열을 만들 수 있습니다.
const text = "ABCDE";
const result = text.slice(0, 1) + "XY" + text.slice(3);
console.log(result); // "AXYDE"
console.log(text); // "ABCDE"
B와 C를 제외하고, 그 자리에 XY를 연결한 예제입니다.
9. 어떤 메서드를 선택하면 좋을까?
| 하고 싶은 작업 | 선택할 메서드 |
|---|---|
| 문자열의 일부 가져오기 | slice() 또는 substring() |
| 뒤에서부터 문자열 가져오기 | slice() |
| 두 인덱스의 순서에 상관없이 사이 구간 가져오기 | substring() |
| 배열의 일부를 새 배열로 가져오기 | slice() |
| 배열을 직접 삭제·추가·교체하기 | splice() |
| 기존 코드의 “시작 위치부터 길이만큼 추출” 이해하기 | substr() |
이름을 외우기보다, 호출 코드를 볼 때 대상이 문자열인지 배열인지, 두 번째 숫자가 위치인지 개수인지, 원본이 바뀌는지를 먼저 확인해 보세요. 같은 숫자를 전달했는데 다른 결과가 나오는 이유를 이해하기가 훨씬 쉬워집니다.
참고 자료
'프론트엔드 > JavaScript' 카테고리의 다른 글
| [ JavaScript ] filter(): 빈 문자열은 왜 제거되고, 공백은 왜 남을까? (0) | 2026.10.13 |
|---|---|
| [ JavaScript ] sort() 메서드와 sort((a, b) => a - b)의 차이점 (0) | 2025.01.29 |
| [ JavaScript ] findIndex와 indexOf의 차이점 알아보기 (0) | 2024.10.17 |
| [ javascript ] HTML, CSS, JS로 음악 플레이어 만들기 (7) | 2024.09.09 |
| [ Javascript ] Drop Down(드롭다운) 메뉴 만들기 (2) | 2024.04.23 |
댓글