1. 그들이 건들지 못하게 하라
나는 안드로이드 개발할 때도 약간 변태 같은 습성이 있었는데
바로 사람들이 구성한 라이브러리의 내부를 일일이 뜯어보는 것이었다.
라이브러리나 프레임워크나 결국 다른 언어로 만들어진 덩어리일 뿐이기에
항상 나는 추상화된 코드 밑에 어떤 마법들이 일어나고 있는지 파악하고 싶었다.
프론트엔드를 공부하고 있는 지금은 React 라이브러리에 큰 관심이 있는데
톺아볼 요량으로 패스트캠퍼스의 React 라이브러리의 초기 버전을 구현하는 수업을 들었다.
(https://fastcampus.co.kr/dev_academy_kmt2)
이 강의 뿐만 아니라 유튜브(https://youtu.be/Z7ysKNFrMqo)에서 보고 배운 것이 있는데
바로 Object.seal()과 Object.freeze()이다.
리액트가 제공하는 객체는 희한하게도 수정이 안된다.
그 이유는 해당 객체가 "Freezed" 되어있기 때문인데, Object.freeze를 통해 해당 객체를 수정하지 못하게 할 수 있다.
Object 클래스가 가지고 있는 모든 메서드를 외울 수는 없지만, 이 메서드는 알고 있으면 좋을 듯하다.
내가 만든 어떤 객체가 누군가가 임의로 바꿀 수 있으면 위험한 상황에는 굉장히 중요하기 때문이다.
2. const, Object.seal, Object.freeze 차이
const는 ES6(ECMA 2015)부터 지원하는 문법으로 현대 브라우저라면 대부분 지원한다.
예전에는 var보다 느리다는 악평(?)이 있었지만 현재는 수정된 이슈이다.
const로 선언하는 것들은 모두 "상수"로 된다고 처음에 배우지만,
엄밀히 말해서는 객체(Object) 형태의 내부는 모두 재할당부터 수정까지 가능하다.
설명 안 한다. 바로 예시부터 들어가 보자
(1) 빈 객체에 냅다 값 넣어보기
const exampleObject = {};
exampleObject.key = 'value';
// 비어있는 객체에 key라는 키에 "value"라는 문자열 값을 넣음
console.log(exampleObject)
// {key: 'value'} 라는 값이 나온다.
나는 분명히 const로 선언했는데 객체 내부로 직접 값을 할당하니까 할당이 된다?!
(2) 원래 값이 있던 순서쌍을 수정해 보기
const exampleObject = { key: "first value"}; // 하나의 객체를 탄생시킨다.
exampleObject.key = "New value"
// 원래 있던 "first value"의 값을 새로운 "New value"로 수정
console.log(exampleObject)
// key: "New value"가 되었다.
당연히 된다. 위가 되면 아래도 되는 것이 논리적으로 추측 가능하다.
그런데, 여기서 안 되는 것이 있긴 하다. 바로 해당 변수에 대한 재할당이 안된다.
(3) const가 가진 유일한 방패
const exampleObject = { key: "first" }
exampleObject = {key: "New Key"} // 에러 발생!!!!!
이번 경우에는 에러가 발생한다.
Uncaught TypeError: Assignment to constant variable. at <anonymous>:코드줄번호
이유는, 자바스크립트 스펙상 const로 선언된 변수는 재할당이 금지되어 있기 때문이다.
그러니까 우리가 처음에 자바스크립트를 배울 때 const를 재할당이 안된다고 이해했다면 정확히 이해한 것이고
안에 들어가 있는 값이 아예 변할 수 없다고 인지하면 크게 문제가 될 수 있다는 것이다.
그런데 자바스크립트 언어에서 이미 할당되어 있는 값을 수정할 수 없게 만들어두었을까?
자바스크립트 자체가 형편없고 이상하다는 평가가 많지만, 그 정도는 아니다.
(4) Object.seal()
Object 클래스에 있는 메서드 중에서는 seal()이라는 것이 있는데, 여기 안에 매개변수로 객체를 주면 해당 객체는
ㄱ. 새로운 속성을 추가할 수 없으며
ㄴ. 현재 존재하는 모든 속성을 설정 불가능 상태로 만들어준다.
그런데 예외가 되는 것은
"쓰기 가능한 속성의 값은 변경할 수 있다."
이게 무슨 말인지 예시로 알아보자.
우선 ㄱ와 ㄴ을 살펴본다.
23살의 홍길동은 성공해서 서울과 경기도에 자기 아파트가 있다.
let exampleObject = { name: "홍길동", age: 23, houseLocation: ["서울", "경기도"] }
Object.seal(exampleObject) // 밀봉!
exampleObject.pants = "blue" // 새로운 키와 값을 쌍으로 추가!!
console.log(exampleObject)
// { name: "홍길동", age: 23, houseLocation: ["서울", "경기도"] }
// pants의 값이 추가되지 않았다.
여기서 seal을 수행하고 새로운 속성을 추가해 보자, 예를 들어 바지 색상이 파란색이다.
새로운 속성을 추가하려 했으나 아무 오류도 내지 않고 추가되지 않았다. 이미 밀봉된 상태에서는 새로운 속성을 받아들이지 않는다.
또한 삭제도 안된다. delete exampleObject.name을 해도 그대로 값이 출력된다.
delete exampleObject.name
console.log(exampleObject)
// { name: "홍길동", age: 23, houseLocation: ["서울", "경기도"] }
그럼 뭐가 될까? 값의 수정은 된다.
홍길동이 한 살 더 먹어서 24살로 되었다고 가정해 보자.
exampleObject.age = 24
console.log(exampleObject)
// { name: '홍길동', age: 24, houseLocation: ['서울', '경기도'] }
- 참고: exampleObject안에 있는 houseLocation은 배열로 그 자체가 또 객체이다. 이 객체 내부는 seal이 적용된 상태가 아니므로 수정과 삭제가 모두 가능하다. (delete exampleObject.houseLocation[1]이 가능)
- 위가 불가능하게 하려면 반복문을 통해 해당 객체의 모든 요소를 하나하나 돌면서 일일이 다 봉인해야 한다.
(5) Object.freeze()
freeze는 거의 다 위의 seal()과 같다.
다른 점은 해당 값의 변경도 안된다는 것이다.
let exampleObject = { name: "홍길동", age: 23, houseLocation: ["서울", "경기도"] };
Object.freeze(exampleObject);
exampleObject.age = 24;
console.log(exampleObject)
// {name: '홍길동', age: 23, houseLocation: ["서울", "경기도"] }// 해당 값은 변하지 않는다.
3. 읽어볼 만한 글
1. Object 클래스와 내부의 모든 메서드
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object
2. Object.seal()
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/seal
3. Object.freeze()
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
끝!