JavaScript에서 숫자 배열에 sort()만 호출하면 숫자 크기가 아니라 문자열 기준으로 순서를 정합니다. 유한한 Number 값만 있는 배열을 숫자 오름차순으로 정렬하려면 sort((a, b) => a - b)를 씁니다. 원본을 남겨야 한다면 복사한 배열에 적용하세요.
같은 입력을 두 기준으로 정렬하면
AI가 만든 정렬 코드의 결과가 낯설다면, 비교 함수를 빼고 넣은 결과부터 나란히 보세요. 아래는 실제 주문이나 고객 자료가 아닌 짧은 합성 배열입니다.
const numbers = [10, 2, 1, 20];
const byDefault = [...numbers].sort();
const ascending = [...numbers].sort((a, b) => a - b);
console.log(JSON.stringify(byDefault)); // [1,10,2,20]
console.log(JSON.stringify(ascending)); // [1,2,10,20]
console.log(typeof byDefault[1]); // number
기본 정렬은 [1,10,2,20], 숫자 비교 함수를 넣은 정렬은 [1,2,10,20]입니다. 비교할 때 문자열 기준을 쓴다고 배열 안의 숫자 자체가 문자열로 바뀌는 것은 아닙니다. 첫 결과에서 10의 타입을 읽으면 여전히 number입니다.

10이 먼저 놓이는 이유
기본 sort()는 이 예제의 숫자를 문자열로 바꿔 비교합니다. 문자열 "10"과 "2"의 첫 글자는 각각 "1"과 "2"입니다. UTF-16 코드 단위 순서에서 "1"이 앞서므로 "10"도 "2"보다 앞에 놓입니다. 여기서 UTF-16은 JavaScript가 문자열을 비교할 때 쓰는 코드 단위 기준입니다.
숫자 크기와 문자열 순서는 다른 기준입니다. [1,2,3]처럼 한 자리 양의 정수만 넣어 확인하면 차이가 드러나지 않을 수 있습니다. 예제처럼 10과 2를 함께 넣으면 두 기준을 구별하기 쉽습니다.
MDN의 기본 정렬 설명에서 해당 규칙을 확인할 수 있습니다.

비교 함수는 참·거짓이 아니라 부호를 돌려줍니다
sort()의 비교 함수가 음수를 반환하면 a가 b보다 앞에, 양수를 반환하면 뒤에 놓입니다. 0이면 두 값을 정렬 기준상 같다고 취급합니다. 숫자 오름차순에서는 a - b가 이 부호를 만들어 줍니다.
console.log(10 - 2); // 8
console.log(2 - 10); // -8
console.log(2 - 2); // 0
const values = [10, 2, 1, 20];
console.log(JSON.stringify([...values].sort((a, b) => b - a)));
// [20,10,2,1]
10 - 2는 양수이므로 10이 2보다 뒤에 갑니다. 2 - 10은 음수이므로 2가 앞에 갑니다. 내림차순은 b - a처럼 뺄 순서를 반대로 둡니다. (a, b) => a > b처럼 참·거짓만 반환하는 식으로 바꾸지 마세요. 비교 함수가 요구하는 음수·0·양수의 역할과 다릅니다.
MDN의 비교 함수 반환값 설명에서 해당 규칙을 확인할 수 있습니다.
결과 변수에 담아도 원본은 바뀝니다
숫자순 정렬과 원본 보존은 따로 결정해야 합니다. sort()는 원래 배열을 정렬하고, 바로 그 배열을 반환합니다. 결과를 새 변수에 받는 것만으로 복사본이 생기지는 않습니다.
const original = [10, 2, 1, 20];
const returned = original.sort((a, b) => a - b);
console.log(JSON.stringify(original)); // [1,2,10,20]
console.log(returned === original); // true
const kept = [10, 2, 1, 20];
const sortedCopy = [...kept].sort((a, b) => a - b);
console.log(JSON.stringify(kept)); // [10,2,1,20]
console.log(JSON.stringify(sortedCopy)); // [1,2,10,20]
console.log(sortedCopy === kept); // false
첫 비교가 true인 이유는 returned와 original이 같은 배열을 가리키기 때문입니다. 원본을 남겨야 할 때는 뒤 예제처럼 [...kept]로 새 배열을 만든 뒤 그 배열을 정렬합니다. 이 글은 숫자 원시값만 다루며, 객체가 들어 있는 배열의 깊은 복사를 설명하는 예제가 아닙니다.
MDN의 sort 반환값 설명에서 해당 규칙을 확인할 수 있습니다.

문자열 메서드와도 구분해야 합니다. replaceAll()은 새 문자열을 반환하지만, 이 글의 sort()는 원래 배열을 바꿉니다. 메서드 이름이나 결과 변수의 유무만 보고 원본 보존 여부를 판단하지 마세요.
replaceAll의 반환값과 원문을 구분한 예제와 원본 변경 여부를 비교해 볼 수 있습니다.
AI에게 다시 요청할 때는 기대 출력도 적으세요
“정렬이 이상해”보다 입력과 기대 출력을 함께 주면 고칠 기준이 분명해집니다. 다음은 설명용 요청문입니다.
[10, 2, 1, 20]을 숫자 오름차순 [1, 2, 10, 20]으로 정렬해 줘. 원래 배열은 그대로 두고 새 배열을 반환해 줘. 기본 sort()만 쓴 결과와 비교 함수로 정렬한 결과도 각각 출력해 줘.
코드를 받은 뒤에는 두 자릿수 값이 섞인 순서와 원본 배열을 함께 확인하세요. 이 예제의 범위는 유한한 Number 값으로 채운 배열입니다. 문자열·객체·BigInt, NaN·Infinity, 빈 슬롯이 섞인 입력에는 이 설명을 그대로 확대하지 않습니다.
2026년 10월 31일 Windows x64의 Aside 브라우저에서 본문 코드 3블록을 그대로 실행해 출력을 확인했습니다. User-Agent가 보고한 Chrome 버전은 154.0.0.0입니다. 음수·소수·중복 값, 빈 배열과 단일 값도 별도 합성 입력으로 확인했습니다. 이 버전 문자열은 브라우저의 보고값이며 실제 사용자 서비스나 다른 브라우저 전체를 검증한 결과는 아닙니다.
출처 및 확인일
- MDN Web Docs, Array.prototype.sort(). 게시·수정일 미표기. 확인: 2026-10-31 KST.
- Ecma International / TC39, ECMAScript® 2027 Language Specification: Array.prototype.sort. 관찰 시점 living draft, 조항별 게시·수정일 미표기. 확인: 2026-10-31 KST.
'💻IT' 카테고리의 다른 글
| API temperature=0 설정해도 응답이 다른 이유 (LLM 재현성 해결법) (0) | 2026.11.01 |
|---|---|
| JavaScript forEach에 await 안 먹히는 이유와 비동기 해결법 (for...of) (0) | 2026.11.01 |
| HTML button 클릭 시 form 자동 제출 방지 (type="button" 기본값 차이) (0) | 2026.10.26 |
| Flex 카드 말줄임이 안 되면, 제목을 감싼 요소부터 보세요 (0) | 2026.10.26 |
| replaceAll을 썼는데 그대로라면, 반환값부터 보세요 (0) | 2026.10.25 |
