티스토리 뷰
1.불변성?
객체는 참조 형태로 값을 주고 받는데, 하나의 객체가 생성되고 그 값을 다른 객체들이 참조 하고 있다면 의도 하지 않은 값의 변형으로 문제가 발생하는 경우가 있을 수 있다. 보통 이런 경우 레퍼런스를 참조한 다른 객체에서 객체를 변경 하기 때문이다. 이와 같은 문제를 방지 하기 위해서는 불변의(immutable) 객체를 만들거나 객체 복사를 통해 새로운 객체를 생성 한 후 변경하는 것이 안전하다.
let a = 10;
let b = a;
a = 20;
console.log(a,b); //20 10
위 코드는 변수 a에 10을 할당하고, 변수 b는 a가 가리키는 주소를 가리킨다. 이때 a를 20으로 변경하면 a와 b모두 20이 아닌 a만 20으로 바뀌게된다.
이유는 Boolean, Numbe, String, null, undefined, Symbol 과 같은 타입은 기본적으로 불변성을 유지하기 때문이다.
이와 반대로 Object 타입들은 변경가능한 값이다.
2.객체 타입의 불변성을 지키려면..
(2-1) 스프레드 문법 사용
// 스프레드 문법을 사용하여 객체를 복사해야지 객체가 불변성을 유지 할 수 있다.
let info = { name:'a', age:28 };
let new_info = {...info};
info.name = 'b';
console.log(info.name, new_info.name); //b a
// 하지만 1레벨 깊이에서만 유효하게 동작하기 때문에 객체 내부의 객체의 불변성까지는 유지할수 없다.
let info = { name:'a', fake:{age:28} };
let new_info = {...info};
info.fake.age = 30;
console.log(info.fake.age, new_info.fake.age); //30 30
=> 만약 2레벨 이상의 깊이에서 불변성을 유지해주려면
별도의 변수에 래벨별 값을 재할당하고 다시 복사한 객체의 값에 넣어주는 작업을 반복해야한다.
(2-2) Object 메서드 사용
// Object.assign() 메서드는 타깃 객체의 속성만을 대상으로 객체로 복사 한다.
// 하지만 1레벨 깊이에서만 유효하게 동작하기 때문에 객체 내부의 객체의 불변성까지는 유지할수 없다.
let o1 = { a: 1 };
let o2 = { b: 2 };
let obj1 = Object.assing({},o1,o2);
console.log(obj1, o1); // {a:1,b:2} {a:1}
let o3 = { a:1 };
let o4 = { b:2 };
let o5 = { c:3 };
let obj2 = Object.assign(o3,o4,o5);
console.log(obj2, o3); // {a:1,b:2,c:3} {a:1,b:2,c:3}
// => 이처럼 타겟 객체 자체가 변경됨
// Object.freeze() 메서드를 사용하면 더 이상 수정할 수 없는 불변성의 객체를 만들 수 있다.
let o1 = { a: 1 };
let obj1 = Object.freeze(o1);
o1.a = 10; //재할당 불가
console.log(o1); //Error
// 하지만 Object.assign 와 마찬가지로 객체 내부의 객체에는 대응 하지 못한다.
// => 이경우 deepFreeze 해야한다.
const user = {
name: 'Jack',
body: {
weight: 100
}
}
Object.freeze(user)
user.body.weight = 200 // 재할당 가능하다.
console.log(user) // { user: 'Jack', body: { weight: 200 } }
function deepFreeze(obj) {
const props = Object.getOwnPropertyNames(obj)
props.forEach((name) => {
const prop = obj[name]
if (typeof prop === 'object'&& prop! == null) {
deepFreeze(prop)
}
})
return Object.freeze(obj)
}
const user = {
name: 'Jack',
body: {
weight: 100
}
}
deepFreeze(user)
user.name = 'Jack' // 재할당 불가
user.body.weight = 200 // 재할당 불가
console.log(user) // 오류
Object.assign과 Object.freeze을 사용하여 완전한 불변 객체를 만드는 방법은 추가 비용이 들기도 하고 성능상 이슈가 있어서 큰 객체에는 사용하지 않는 것이 좋다.
(2-3) Immutable 라이브러리 사용
Immutable js에서 Map은 객체 대신 사용하는 데이터 구조이다. (자바스크립트의 내장함수 Map과는 다르다.)
const { Map, fromJS } = require('immutable');
//ImmutableJS에서 Map은 객체 대신 사용하는 데이터구조이다
const m1 = Map({ a: 1, b: 2, });
const m2 = Map({ a: 1, b: Map({ c: 'hello', d: 10, }), e: 11, });
//m2와 같이 내부에 일일이 그 내부까지 Map으로 만들기 힘들떄 fromJS를 사용한다.
//fromJS를 사용하면 내부 배열은 List로 만들고, 내부 객체는 Map으로 만든다.
const m3 = fromJS({ a: 1, b: { c: 'hello', d: 10, }, e: 11, });
//Immutable 객체를 일반 객체 형태로 변형
const m4 = m2.toJS();
'JavaScript' 카테고리의 다른 글
JS - JSX? (0) | 2022.03.31 |
---|---|
JS - Map() 과 Set() (0) | 2022.03.02 |
JS - 함수 (일반, 리터럴-익명) (3) | 2022.02.21 |
JS - 배열 메소드 (forEach, some, every, map, reduce, filter) (4) | 2022.02.21 |
JS - 동기, 비동기 (0) | 2022.02.19 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 호이스팅
- React로 쓰로틀링 디바운싱 구현
- debouncing
- 가상스크롤
- 1급 함수
- react
- 렌더링 속도 개선
- Virtual Scroll
- redirects
- 시맨틱 웹
- array
- redux
- 자바스크립트 동작원리
- 매겨변수와 인자
- javascript
- 함수형 컴포넌트
- typescript
- 자바스크립트 비동기 동작원리
- Next.js
- next.js에 .gitignore가 적용되지 않을 때
- 타입스크립트
- next.js 환경변수
- useRef
- 1급 시민
- rewrites
- 목표 일기
- vue
- 1급 객체
- zustand
- programmers
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
글 보관함