본문 바로가기

비개발자의 개발 일지

현장 팀장에서 수출 ERP까지 — AI와 함께 시스템을 만든 기록

시리즈 보기
php

JavaScript Array 메서드 — concat·join·reverse·sort 완전 정리

by 왕진 2026. 7. 4.
반응형

 

 

Web Development · JavaScript

JavaScript Array 메서드 —
concat·join·reverse·slice·sort 완전 정리

원본을 바꾸는 메서드(mutating)와 새 값을 반환하는 메서드를 구분하는 것이 배열 버그를 막는 핵심이다
시작 오늘 분석할 코드

배열 a 하나를 두고 concat, join, reverse, slice, sort, toString 여섯 개 메서드를 차례로 호출하면서 그때그때 ca가 각각 어떻게 되는지 document.write로 출력해보는 코드다. 겉보기엔 비슷한 "배열을 다루는 메서드"들이지만, 실행 결과를 보면 절반은 원본 a를 조용히 바꿔버린다는 걸 알 수 있다.

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Array 객체의 메소드 활용</title> <script> function pr(msg, arr) { document.write(msg + arr.toString() + "<br>"); } </script> </head> <body> <h3>Array 객체의 메소드 활용</h3> <hr> <script> let a = new Array("황", "김", "이"); let b = new Array("박"); let c; pr("배열 a = ", a); pr("배열 b = ", b); document.write("<hr>"); c = a.concat(b); // c는 a와 b를 연결한 새 배열 pr("c = a.concat(b)후 c = ", c); pr("c = a.concat(b)후 a = ", a); c = a.join("##"); // c는 배열 a를 연결한 문자열 pr("c = a.join() 후 c = ", c); pr("c = a.join() 후 a = ", a); c = a.reverse(); // a.reverse()로 a 자체 변경. c는 배열 pr("c= a.reverse() 후 c = ", c); pr("c= a.reverse() 후 a = ", a); c = a.slice(1, 2); // c는 새 배열 pr("c= a.slice(1, 2) 후 c = ", c); pr("c= a.slice(1, 2) 후 a = ", a); c = a.sort(); // a.sort()는 a 자체 변경. c는 배열 pr("c= a.sort() 후 c = ", c); pr("c= a.sort() 후 a = ", a); c = a.toString(); // toString()은 원소 사이에 ","를 넣어 문자열 생성 document.write("a.toString() : " + c); </script> </body> </html>
실제 출력 미리보기
배열 a = 황,김,이
배열 b = 박

c = a.concat(b)후 c = 황,김,이,박
c = a.concat(b)후 a = 황,김,이 ← 그대로

c = a.join() 후 c = 황##김##이
c = a.join() 후 a = 황,김,이 ← 그대로

c= a.reverse() 후 c = 이,김,황
c= a.reverse() 후 a = 이,김,황 ← 원본이 바뀜!

c= a.slice(1, 2) 후 c =
c= a.slice(1, 2) 후 a = 이,김,황 ← 그대로(이미 reverse된 상태)

c= a.sort() 후 c = 김,이,황
c= a.sort() 후 a = 김,이,황 ← 원본이 또 바뀜!

a.toString() : 김,이,황
※ 배열은 앞선 메서드가 만들어 놓은 상태 위에서 계속 실행된다. reverse() 이후의 모든 결과는 "뒤집힌 a"를 기준으로 하고, sort() 이후는 "정렬된 a"를 기준으로 한다 — 그래서 순서를 바꾸면 결과도 달라진다.
용어 용어 정리
new Array()배열을 생성하는 생성자 문법. ["황","김","이"]와 같은 결과
concat()두 배열을 이어붙인 새 배열을 반환 (원본 유지)
join()배열 원소를 구분자로 이어붙인 문자열을 반환 (원본 유지)
reverse()배열 순서를 뒤집는다. 원본 배열 자체를 변경
slice(s, e)인덱스 s 이상 e 미만을 잘라 새 배열로 반환 (원본 유지)
sort()배열을 정렬한다. 원본 배열 자체를 변경
toString()배열 원소를 콤마로 이어붙인 문자열로 변환 (원본 유지)
mutating method호출만 해도 원본 데이터를 바꿔버리는 메서드 (reverse, sort, push, splice 등)

1 new Array() — 배열을 만드는 또 다른 방법
왜 [ ] 대신 new Array()를 쓰는가?

let a = new Array("황", "김", "이");let a = ["황", "김", "이"];결과가 완전히 동일한 배열을 만든다. Array는 자바스크립트에 내장된 생성자 함수이고, new를 붙여 호출하면 그 인자들을 원소로 갖는 배열 객체가 만들어진다.

new Array("황", "김", "이") → ["황", "김", "이"] new Array("박") → ["박"] (원소 1개짜리 배열)
※ 함정: new Array(3)처럼 숫자 하나만 넘기면 원소가 3인 배열이 아니라 길이가 3인 빈 배열이 만들어진다. 이런 혼동 때문에 실무에서는 배열 리터럴 [ ] 표기를 훨씬 더 많이 쓴다.

2 concat() — 배열을 이어붙인 새 배열
concat은 무엇을 반환하는가?

a.concat(b)a의 모든 원소 뒤에 b의 모든 원소를 이어붙인 완전히 새로운 배열을 만들어 반환한다. ab는 손끝 하나 건드리지 않는다.

a = ["황","김","이"], b = ["박"] c = a.concat(b) c → ["황","김","이","박"] ← 새 배열 a → ["황","김","이"] ← 그대로
※ 여러 배열을 한 번에 합칠 수도 있다 — a.concat(b, c, d)처럼 인자를 계속 늘리면 된다. 참고로 최신 코드에서는 전개 연산자 [...a, ...b]로 같은 결과를 만들기도 한다.

3 join() — 배열을 문자열로 접합
join("##")의 "##"는 무슨 역할인가?

join()은 배열의 모든 원소를 하나의 문자열로 합친다. 괄호 안의 값은 원소 사이에 끼워 넣을 구분자(separator)다. a.join("##")은 "황##김##이"라는 문자열 하나를 만든다 — 배열이 아니라 문자열이라는 점이 중요하다.

a = ["황","김","이"] a.join("##") → "황##김##이" (문자열) a.join("-") → "황-김-이" a.join() → "황,김,이" (구분자 생략 시 기본값은 콤마)
join() 이후에도 a는 배열 그대로다. 결과가 문자열이라는 것과 원본이 안 바뀐다는 것, 두 가지를 함께 기억해야 한다.

 

반응형

 

4 reverse() — 원본 배열 자체를 뒤집는다
왜 reverse()는 위험한가?

reverse()는 앞서 본 concat·join과 근본적으로 다르다. 새 배열을 만들어 돌려주는 게 아니라, a 자체의 원소 순서를 제자리에서 뒤집어버린다. 반환값 c는 사실 새로운 무언가가 아니라 뒤집힌 a를 가리키는 같은 참조일 뿐이다.

c = a.reverse() 실행 후 c → ["이","김","황"] a → ["이","김","황"] ← 원본이 그대로 바뀌었다! c와 a는 완전히 같은 배열을 가리키는 두 이름이다.
※ 원본을 지키고 싶다면
  • 먼저 복사본을 만든 뒤 뒤집는다: let c = [...a].reverse();
  • 이렇게 하면 a는 그대로, c만 뒤집힌 새 배열이 된다
  • "원본을 바꾸는 메서드"라는 사실을 모르고 쓰면 이후 코드에서 예상치 못한 순서로 데이터를 다루게 된다

5 slice() — 원본은 그대로, 일부만 새 배열로
slice(1, 2)는 어디부터 어디까지인가?

slice(시작, 끝)시작 인덱스부터 끝 인덱스 "직전"까지를 잘라 새 배열로 반환한다. 이 코드에서 a는 이미 reverse()로 뒤집힌 상태(["이","김","황"])이므로, a.slice(1, 2)는 인덱스 1번 원소인 "김" 하나만 담은 배열을 만든다.

a = ["이","김","황"] (reverse 이후 상태) 인덱스: 0 1 2 a.slice(1, 2) → ["김"] (인덱스 1만, 2는 미포함) a → ["이","김","황"] ← 그대로
slice() — 원본 유지
새 배열을 반환한다.
원본 a는 절대 바뀌지 않는다.
안전하게 "일부만 꺼내보기"용.
splice() — 원본 변경 (참고)
이름은 비슷하지만 전혀 다른 메서드.
a에서 실제로 원소를 삭제·삽입한다.
이번 코드에는 등장하지 않지만 헷갈리기 쉽다.

6 sort() — 원본 배열 자체를 정렬한다
sort()도 reverse()처럼 원본을 바꾼다

sort()reverse()와 같은 성격의 메서드다. a 자체의 원소 순서를 정렬해서 바꿔버리고, 그 바뀐 a를 그대로 반환한다. 이 코드에서는 문자열을 유니코드 코드값 기준 오름차순으로 정렬하므로 "김" → "이" → "황" 순서가 된다.

c = a.sort() 실행 후 (직전 상태: ["이","김","황"]) c → ["김","이","황"] a → ["김","이","황"] ← 원본이 또 한 번 바뀌었다!
※ 숫자 배열을 sort()하면 더 위험하다. 기본 sort()는 각 원소를 문자열로 취급해 정렬하기 때문에 [10, 2, 1].sort()[1, 10, 2]가 되어버린다. 숫자를 정렬하려면 반드시 a.sort((x, y) => x - y)처럼 비교 함수를 넣어야 한다.

7 toString() — 배열을 콤마 문자열로
toString()과 join()은 뭐가 다른가?

toString()은 배열의 모든 원소를 콤마(,)로 고정해서 이어붙인 문자열을 만든다. 사실상 구분자를 지정할 수 없는 join()이라고 보면 된다 — 실제로 a.toString()은 내부적으로 a.join(",")과 같은 값을 만든다.

a = ["김","이","황"] (sort 이후 상태) a.toString() → "김,이,황" a.join(",") → "김,이,황" (완전히 같은 결과)
※ 이 코드의 pr() 함수 자체도 내부에서 arr.toString()을 호출해 배열을 화면에 문자열로 찍고 있다. 배열을 + 연산자로 문자열과 합칠 때도 자바스크립트가 자동으로 toString()을 불러준다.

8 원본 변경 vs 새 값 반환 — 한눈에 정리

여섯 메서드를 "원본을 건드리는가"라는 기준 하나로 다시 묶으면 이렇게 갈린다.

원본 유지 (Non-mutating)
concat() → 새 배열
join() → 새 문자열
slice() → 새 배열
toString() → 새 문자열

안심하고 여러 번 호출해도 된다.
원본 변경 (Mutating)
reverse() → a 자체 변경
sort() → a 자체 변경

호출 한 번으로 이후 모든 코드가 보는 a가 달라진다.
메서드 반환값 원본 a 변경? 한 줄 설명
concat(b) 새 배열 아니오 a와 b를 이어붙인 새 배열 생성
join("##") 문자열 아니오 원소 사이에 구분자를 넣어 문자열화
reverse() 배열(=a) a의 순서를 제자리에서 뒤집음
slice(1, 2) 새 배열 아니오 인덱스 1 이상 2 미만만 추출
sort() 배열(=a) a를 코드값 기준 오름차순 정렬
toString() 문자열 아니오 콤마로 이어붙인 문자열화 (join(",")와 동일)
※ 왜 이 구분이 버그의 원인이 되는가: reverse()sort()를 호출한 뒤 "원본 a는 그대로일 것"이라고 착각하고 뒤에서 계속 a를 쓰면, 실제로는 이미 순서가 바뀐 a를 쓰게 되어 화면 출력·계산 결과가 의도와 다르게 어긋난다.

9 자주 하는 실수
실수 증상 해결
reverse()·sort()가 원본을 바꾸는 걸 모름 메서드 호출 후 a를 다시 쓰는 코드에서 값이 예상과 다름 두 메서드는 mutating이라는 것을 암기, 필요하면 [...a]로 복사 후 사용
slice()splice() 혼동 원본을 지키려고 slice를 썼는데 실제론 splice를 써서 원본이 삭제됨 이름이 비슷할 뿐 완전히 다른 메서드임을 구분해서 기억
join() 인자를 생략하고 다른 구분자를 기대함 결과가 항상 콤마(,)로 이어짐 구분자가 필요하면 join("원하는 문자")로 명시
숫자 배열에 sort()만 호출 [10, 2, 1][1, 10, 2]처럼 문자열 기준으로 정렬됨 비교 함수 a.sort((x, y) => x - y) 사용
concat()이 원본을 합쳐준다고 착각 a.concat(b)만 호출하고 결과를 안 받으면 아무 변화도 없음 concat은 반환값을 반드시 변수에 담아 사용 (c = a.concat(b))
new Array(숫자)를 원소가 담긴 배열로 착각 new Array(3)[3]이 아니라 길이 3의 빈 배열이 됨 원소를 직접 넣을 땐 배열 리터럴 [3] 또는 new Array(1,2,3)처럼 인자 2개 이상 사용

핵심 한 줄 요약

new Array()배열 리터럴 [ ]과 동일한 배열 생성 문법
concat(b)새 배열 반환 — 원본 유지
join(구분자)새 문자열 반환 — 원본 유지
reverse()원본 a 자체를 뒤집음 — mutating
slice(시작, 끝)새 배열 반환 — 원본 유지
sort()원본 a 자체를 정렬함 — mutating
toString()콤마로 이어붙인 새 문자열 반환 — 원본 유지
기억할 것원본을 지키려면 항상 [...a]로 복사 후 mutating 메서드 사용

Tags

#JavaScript #배열 #Array #concat #join #reverse #slice #sort #toString #배열메서드 #자바스크립트기초 #mutating #JS #웹개발 #티스토리
▼ 티스토리 태그 입력란 복사용
JavaScript, 배열, Array, concat, join, reverse, slice, sort, toString, 배열메서드, 자바스크립트기초, mutating, JS, 웹개발, 티스토리
반응형

댓글