-
console.log() 실시간 적용언어 공부/JS 2022. 4. 6. 16:54
js공부를 하는 중 배열 안에 객체가 들어있는 자료형을 다뤄봤다.
let userList = [ { name: "Mike", age: 30 }, { name: "Jane", age: 27 }, { name: "Tom", age: 18 }, ];
이런 구조였는데, 여기에 userList의 객체의 속성은 유지한 채 새로운 속성을 추가하고 싶을 때
map()
과Object.assign()
을 사용하게 된다.map()
함수를 인자로 받아서 배열 모든 원소에 대해 함수의 기능을 실행한 뒤 새로운 배열로 반환해주는 함수이다.Object.assign()
객체 들을 인자로 받는데, 첫 번째 객체인 타겟 객체에 두 번째 이후의 객체의 요소들을 추가하는 것이다.적용된 예시는 다음과 같다.
let newUserList = userList.map(function (item, idx) { return Object.assign({}, item, { id: idx + 1, isAdult: item.age > 19, }); });
여기까지는 문제 되는 부분이 없다. 기본적인 map와 assign의 활용인데, 공부하던 중 의문점이 든 부분은 다음이었다.
console.log()
로userList
를 찍어 본 다음에userList[1].name
의 값을 변경하고 다시console.log()
을 찍으면 다음과 같은 결과가 나온다.변경하기 전에 찍은 console.log()도 값이 변경되서 출력된다.
이게 왜 그런가 해서 찾아봤더니
console.log()는 참조를 로깅하기 때문에, 객체와 같이 내용물이 실시간으로 바뀔 수 있는 것들은 내용이 실시간으로 바뀌기 때문
이랬다.
(참고로 배열도
typeof
을 써보면 알듯이 일단은 객체이다.)이런 console.log()의 실수를 겪지 않으려면 두 가지의 해결법이 있다.
- 객체가 아닌 값을 로깅한다.
- 객체를 깊은 복사를 한 후 로깅한다.
1번의 경우는 자명하다. 실제로
let a = 1;
하고 / 로깅하고 /a = 2;
하고 / 로깅하고 났을 때의 값은 달랐으니까.그렇다면 2번의 경우는 어떻게 하는 것일까?
배열의 경우엔
slice()
, 객체의 경우엔assign()
등등, 간단한 방법이 있겠지만 이는 객체(배열 포함)가 1차원인 경우밖에 제대로 동작하지 않는다. 따라서 제대로된 깊은 복사의 경우는- 모든 경우의 수를 고려하는 재귀함수 구현
JSON.stringfy()
를 사용하여 원본 객체와 참조를 끊은 후JSON.parse()
로 다시 객체화- 외부 라이브러리인 lodash 라이브러리의
_.cloneDeep()
사용
... 와 같은 방법이 있다.
3의 방법이 현업에서는 가장 많이 사용하는 방법이라 이 방법을 사용하는게 좋지만, 공부하는 입장에선... 그닥 도움이 되지 않을거 같다.
따라서 난 새로운 방법으로 구현해봤다. 바로
map()
메서드의 특징와assign()
을 이용해서!앞서 언급했 듯 map()은 새로운 배열을 반환하는 것이다. 따라서 자연스레 깊은 복사가 가능하다.
또한 assign()은 1차원 객체에서 깊은 복사가 가능하다.
구현한 코드는 다음과 같다.
let tmpUserList = userList.map((item) => { return Object.assign({}, item); });
그리고
tmpUserList[1].name
을 바꾸고userList
에tmpUserList
를 대입하면...!<Fig. 2>와의 차이점 이라면 첫 번째 console.log()의 userList에는 기존 userList의 주소가, 두 번째 console.log()의 userList에는 tmpUserList의 주소가 들어가 있다는 것이다.
이런 상황이 실전에서 발생할 일은 드물겠지만 공부하거나, 디버깅하며 로깅 하거나 하는 상황에 발생했을 때 오늘의 나처럼 당황하지 않았으면 한다.
요약
객체의 경우 깊은 복제를 하지 않으면 console.log(로깅할 때) 값이 실시간으로 변한다.
깊은 복사는 lodash 외부 라이브러리를 이용하는게 편하다.'언어 공부 > JS' 카테고리의 다른 글
prototype (0) 2022.04.10 일반 함수로 생성자 함수처럼 구현 (0) 2022.04.07 Closure (0) 2022.04.07