(Javascript) Array 비교 방법
자바스크립트에서 두 배열이 같은지 비교하는 방법을 알아보자.
급한 사람을 위해 결론부터 :)
가장 간단한 방법은 3가지로 배열을 아래처럼 String 형태로 만들어서 비교하는 방법이 가장 쉽다.
- String() 사용
- toString() 사용
- JSON.stringify 사용 (추천)
const arr1 = [1,2,3];
const arr2 = [1,2,3];
// 결과는 셋다 true
console.log( String(arr1) == String(arr2) );
console.log( arr1.toString() == arr2.toString() );
console.log( JSON.stringify(arr1) == JSON.stringify(arr2) );
* 여기서 주의점이 있는데 비교할 배열 안에 Object나 Array가 들어가게 되면 JSON.stringify를 사용해야한다.
// 배열 안에 객체와 배열이 들어감
const arr1 = [{ a : 'hello' }, 1, 2, [1, 2] ];
const arr2 = [{ a : 'bye' }, 1, 2, 1, 2 ];
// 각 방법의 출력 결과
console.log(arr1.toString()); // 결과는 [object Object],1,2,1,2
console.log(String(arr1)); // 결과는 [object Object],1,2,1,2
console.log(JSON.stringify(arr1)); // 결과는 [{"a":"hello"},1,2,[1,2]]
// 문제점
console.log(arr1.toString() == arr2.toString()); // 결과는 true
console.log(String(arr1) == String(arr2)); // 결과는 true
console.log(JSON.stringify(arr1) == JSON.stringify(arr2)) // 결과는 false
자 위의 코드예제를 보면 배열안에 객체나 배열이 들어있을 때, 각각을 콘솔로 찍어보면 아주 중요한 다른점이 보인다.
'.toString()'과 'Sting()'방법을 사용해 string형태로 변환할 경우 배열 내부의 객체와 배열이 우리가 예상한 모습과 조금 다르게 변환되는 것을 볼 수 있다. 따라서 이 두 방법을 사용하게 된다면 서로 다른 배열을 비교했을 때 'true'가 나오는 오류가 생긴다.
반면 'JSON.stringify()'은 객체와 배열을 내부까지 string형태로 잘 변환하기 때문에, 이 방법을 사용하면 더 정확하게 배열을 비교할 수 있다. 따라서 이 방법을 사용하는 것이 더 적합하다.
비교연산자 '=='를 이용하면 안되는걸까?
그냥 ==를 사용하면 안될까? 안된다.
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
console.log(arr1==arr2); // 결과는 false
같은 길이에 같은 값을 가진 두 array를 비교했지만, 결과는 false가 나온다.
이유가 무엇일까? 이를 이해하기 위해선 자바스크립트의 기본 동작 원리를 알아야 한다.
Array의 원리
(어려울 수 있다. 못알아먹겠으면 적당히 때려치자)
자바스크립트에서 배열은 '기본 데이터 형(primitive type)'(undefined, boolean, number, string, bigint, symbol)이 아니라 'Object(reference type)'임을 기억하고 아래의 예시를 한번 보도록 하자. 참조링크(primitive & reference type)
let a = 2;
let b = a;
b = 3; // b를 변경
console.log(a); // 결과는 2 (a는 바뀌지 않는다)
const arr1 = [1,2,3]
const arr2 = arr1;
arr2[0] = 2; // arr2를 변경
console.log(arr1); // 결과는 [2, 2, 3] (arr2가 바뀐다)
자바스크립트는 기본적으로 'call by value'방식으로 동작한다.
따라서 위의 let b = a 부분에서 a에 담긴 값을 복사하여 b에 담게된다. 값을 복사한것이기 때문에 b를 바꿔도 원본인 a는 바뀌지 않는다.
하지만 배열을 다루는 const arr2 = arr1 부분에서는 조금 다르다.
여기서 arr2에는 [1,2,3]이 복사되는 것이 아니라, arr1의 주소값이 복사되어 담기게 된다. 그 이유는 array는 Object 형이기 때문인데, Object는 주소값을 참조하는 reference type이기 때문이다.
쉽게 설명하면 array는 '기본 데이터 형'을 담을 때와는 다르게 실제 값을 다른곳에 저장하고 그 저장된 메모리의 위치를 가리키는 주소값을 담는 방식이다.
즉, arr1이 가리키고있는 [1,2,3]이 실제로 저장된 주소값을 arr2에 복사하여 담았기 때문에 arr2[0]는 [1,2,3]의 첫번째 요소인 '1'을 가리키게 된다. 따라서 arr2[0] = 2를 하게되면 [1,2,3]이 [2,2,3]로 바뀐다.
그래서 왜 ==은 안되냐고?
자, 멀리도 돌아왔다ㅠ 아래의 예제를 다시한번 보자
const arr1 = [1,2,3]; // 주소값 : 0x12
const arr2 = [1,2,3]; // 주소값 : 0x13
위에서 알아본 바에 따르면 arr1에는 [1,2,3]을 가리키는 주소값(0x12)이 들어갈 것이고, arr2에는 [1,2,3]을 가리키는 주소값(0x13)이 들어갈 것이다.
짜잔, 다른점이 보이는가?
두 배열의 주소값이 다른것을 발견했을 것이다. 같은 길이에 같은 값을 가지는 배열이지만 할당을 따로했기에 주소값이 다른 것이다.
결론
따라서 '=='을 사용하게 되면 두 배열의 주소값을 비교하게 되고, 두 값이 다르니 false를 뱉어내는 것이다!
그래서 처음에 배열의 주소값이 아닌 실제 값을 비교하기 위해서 '기본 데이터 형'인 String으로 변환하는 방법을 사용했던 것이다.
이해가 안간다면 참고링크를 한번씩 읽어보는것도 도움이 될 듯 하다.
오류 지적은 언제나 환영입니다 :)
참고 링크 :
자바스크립트 primitive type & reference type - https://ryulog.tistory.com/140
자바스크립트 자료형 - https://developer.mozilla.org/ko/docs/Web/JavaScript/Data_structures
'call by value' vs 'call by reference' - https://perfectacle.github.io/2017/10/30/js-014-call-by-value-vs-call-by-reference/
Javascript array: value vs reference - https://www.dyn-web.com/javascript/arrays/value-vs-reference.php
'프론트엔드 > Javascript' 카테고리의 다른 글
자주쓰는 정규식 표현들 모음 (0) | 2022.01.11 |
---|
댓글