이번 포스팅에서 설명할 내용은 다음과 같다.🎯
- private class field는 왜 사용할까?
- getter/setter는 왜 사용할까?
- private class field로 선언된 객체타입 멤버변수는 불변성을 유지할까?
private class field를 사용한 예와 사용하지 않은 예를 비교해보고 차이점을 알아가보자.🤔
class CrewProfile {
constructor(name, nickname) {
this.name = name;
this.nickname = nickname;
}
}
//1번
const juunzzi = new CrewProfile("장준혁", "juunzzi");
console.log(juunzzi); // CrewProfile {name: '장준혁', nickname: 'juunzzi'}
//2번
juunzzi.name = "김상록"
juunzzi.nickname = "lokba";
console.log(juunzzi); // CrewProfile {name: '김상록', nickname: 'lokba'}
1번의 코드를 실행하게 되면, juunzzi 인스턴스에는 { name : "장준혁", nickname : "juunzzi" } 의 데이터가 담겨있다.
2번의 코드를 실행하게 되면, 놀랍게도 juunzzi 인스턴스에는 { name : "김상록", nickname : "lokba" } 의 데이터가 담겨있다.
외부에서 juunzzi 인스턴스에 접근이 가능한 것이다.
해당 예시는 가볍게 만들었지만, class에 담겨있는 데이터가 민감한 데이터라면 큰 리스크를 초래할 수 있다.
class의 프로퍼티들은 기본적으로 public인 상태이며, class 외부에서 접근하여 수정할 수 있다.
이러한 점때문에, ES2019에서부터 # prefix를 이용하여 private class field를 선언할 수 있다.
class CrewProfile {
#name;
#nickname;
constructor(name, nickname) {
this.#name = name;
this.#nickname = nickname;
}
}
const lokba = new CrewProfile("김상록", "lokba");
//1번
lokba.#nickname = "juunzzi"; // Private field '#nickname' must be declared in an enclosing class
1번의 코드처럼, 외부에서 해당 멤버에 접근하게 되면 에러 메세지를 출력하게 된다.
private class field를 잘 활용하면 민감한 데이터의 정보은닉이 가능하다.👍
getter/setter를 사용한 예와 사용하지 않은 예를 비교해보고 차이점을 알아가보자.🤔
const crew = {
name: "김상록",
nickname: "lokba",
getProfile() {
return `name : ${this.name}, nickname : ${this.nickname}`;
},
setProfile(value) {
[this.name, this.nickname] = value.split(" ");
},
};
//1번
console.log(crew); // {name: '김상록', nickname: 'lokba', getProfile: ƒ, setProfile: ƒ}
const crew = {
name: "김상록",
nickname: "lokba",
get profile() {
return `name : ${this.name}, nickname : ${this.nickname}`;
},
set profile(value) {
[this.name, this.nickname] = value.split(" ");
console.log(this);
},
};
//2번
console.log(crew); // {name: '김상록', nickname: 'lokba'}
1번과 2번의 출력결과가 다르다.
getter/setter를 사용한 경우, getter/setter 메서드가 출력되지 않는다.
그 이유는 getter와 setter 메서드를 구현하면 객체에는 profile이라는 '가상’의 프로퍼티가 생기는데,
가상의 프로퍼티는 읽고 쓸 순 있지만 실제로는 존재하지 않는다.
외부에 노출이 되지 않기 때문에 장점이다.👍
class Crew {
#profile;
set profile(profile) {
this.#profile = profile;
}
get profile() {
return this.#profile;
}
}
const lokba = new Crew();
lokba.profile = { nickname: "lokba", name: "김상록", age: 26};
//1번
console.log(lokba.profile); //{nickname: 'lokba', name: '김상록', age: 26}
const copyProfile = lokba.profile;
copyProfile.name = "장준혁";
copyProfile.nickname = "juunzzi";
//2번
console.log(copyProfile); //{nickname: 'juunzzi', name: '장준혁', age: 26}
console.log(lokba.profile); //{nickname: 'juunzzi', name: '장준혁', age: 26}
1번과 2번의 결과를 통해 알 수 있는것은, private field는 불변성을 유지하지 않는다.
private class field는 외부 접근을 막을 뿐이지, 불변성과는 관계가 없다
class Crew {
#profile;
set profile(profile) {
this.#profile = profile;
}
get profile() {
//깊은 복사 적용
return JSON.parse(JSON.stringify(this.#profile));
}
}
const lokba = new Crew();
lokba.profile = { nickname: "lokba", name: "김상록", age: 26};
//1번
console.log(lokba.profile); //{nickname: 'lokba', name: '김상록', age: 26}
//2번
const copyProfile = lokba.profile;
copyProfile.name = "장준혁";
copyProfile.nickname = "juunzzi";
console.log(copyProfile); //{nickname: 'juunzzi', name: '장준혁', age: 26}
console.log(lokba.profile); //{nickname: 'lokba', name: '김상록', age: 26}
getter 메서드에 깊은 복사를 적용하니, 2번 코드를 진행한 후에도 불변성이 잘 유지되고 있다.
private class field, getter/setter, 깊은 복사를 활용하면,
외부 접근을 제한할 뿐아니라 getter/setter 메서드 외부 노출 ❌, 데이터를 불변성있게 유지할 수 있다.💯