최근에 진행한 프로젝트에서 Todo List가 있는 컴포넌트를 다른 컴포넌트에서 실시간으로 연동하는 파트를 맡았다. 생성이나 삭제 요청이 발생할 때마다 배열 비교가 필요했고, 객체를 문자열로 변환(JSON.stringfy
)이 필요했다. 특히 순서의 변화도 감지해야 하는 상황이라서.
왜 단순히 동등연산자로 비교할 수 없는가? 이유는 데이터 타입에 있다. 자바스크립트의 타입은 크게 원시형과 참조형으로 나뉜다.
원시형이라 함은,
이렇게 7가지다. 이 타입은 아래와 같은 특징이 있다.
var score = 80; // 선언 및 할당
var scoreCopy = score;
score = 100; // 재할당 : 메모리 위치 변화
console.log(score); //100
console.log(scoreCopy); //80
각 변수는 별개의 메모리 주소에서 각자 원시 '값'을 가지고 있다. 타입, 값 모두 같더라도 값만 전달했으므로 동기화되지 않는다.
cf. 사실 정확히 말하자면 식별자(변수)는 메모리 값이 아니라 주소를 기억한다. 주소는 고유하지만 값은 고유하지 않아서다. 전달 받은 메모리 주소를 통해 메모리 공간에 접근해 값을 참조하고, 그 값을 새 주소에 저장한 것이다.
그러나 차치하고, 다른 공간에 저장된 별개의 값이라서 서로 영향을 주고받지 않는다는 사실이 가장 중요하다.
그럼 객체는 메모리 할당 면에서 어떤 특징을 가질까?
객체는 재할당 없이 직접 값을 변경할 수 있어서 추가, 삭제, 갱신이 가능하다.
이게 뭔 말인가 하면,
var person = {
name: 'k'
};
var person2 = {
name: 'k'
};
위 객체 둘을 그림으로 표현하자면,
말로 풀이하자면 이렇다.
변수가 있는 메모리 공간에 값이 아닌 참조 주소(0x00002320)가 있다.
➡️ 객체는 변수의 메모리 위치는 달라도 프로퍼티가 같다면 똑같은 메모리 주소를 참조할 수 있다.
cf. 물론 원시 값도 엄밀히 말하자면 주소를 기억하는 건 마찬가지이나(주소는 유일무이한데 값 자체는 동일할 수 있어서 헷갈릴 가능성 존재) 주소를 통해 그 값에 접근한다는 점이 다르다.
기존 객체(person)를 복사한 객체(person2) 모두 똑같은 값을 참조(0x00002320)한다.
➡️ 그래서 기존 객체의 값을 바꾸면 복사한 객체도 영향을 받는다.
ex. name 프로퍼티 값을 'P'로 변경 -> person2의 name도 P로 변경됨
이렇다보니 객체에는 아래와 같은 개념이 따라온다.
다시 문제로 돌아와서, 그럼 기존 배열과 새 배열을 비교하려면 어떤 복사를 해야 할까? 바로 깊은 복사다. 할당된 주소가 아닌 객체의 값 내지는 요소를 비교할 수 있도록 문자열 변환 과정이 필요한 것도 이래서다.
끝으로 프로젝트에서 사용한 코드 일부를 예시로 기록하며 자바스크립트 배열 비교 포스팅을 마친다!
// Todo 객체 타입 정의
export interface TodoContent {
todoId: number;
todoContent: string;
todoDate: string;
nickname: string;
userId: number;
}
[];
// Todo 비교
const compareArrays = (arr1: TodoContent[], arr2: TodoContent[]): boolean => {
return JSON.stringify(arr1) === JSON.stringify(arr2);
};
자바스크립트 딥 다이브