자바스크립트에서 public, private ?
자바스크립트는 변수에 접근 제한자 (public, private, protected 등)을 직접 부여하도록 설계되어 있지 않고, 클로저를 이용하여 함수 차원에서 public한 값과 private한 값을 구분하는 것이 가능합니다.
외부에 제공하고자 하는 정보들을 모아서 return 하고, 내부에서만 사용할 정보들은 return 하지 않는 것으로 접근 권한 제어를 할 수 있습니다. 따라서 return 한 변수들은 public, 그렇지 않은 변수들은 private 한 상태가 됩니다.
let outer = function() {
let a = 1;
let inner = function() {
return ++a;
};
return inner; // 함수의 실행 결과가 아닌 함수 반환
};
let outer2 = outer();
console.log(outer2()); // 2
console.log(outer2()); // 3
closure는 사전적으로 닫혀있음, 폐쇄성 정도의 의미를 가지고 있습니다. 위의 코드를 보면 outer 함수는 외부 (전역 스코프)에서 실행하여 return 정보에만 접근할 수 있고, 함수 내부에는 접근할 수 없습니다.
접근 제한자 예제
let car = {
fuel: Math.ceil(Math.random() * 10 + 10),
power: Math.ceil(Math.random() * 3 + 2),
moved: 0,
run: function() {
let km = Math.ceil(Math.random() * 6);
let wasteFuel = km / this.power;
if (this.fuel < wasteFuel) {
console.log('이동불가');
return;
}
this.fuel -= wasteFuel;
this.moved += km;
console.log(km + 'km 이동 (총 ' + this.moved + 'km), 남은 연로 : ' + this.fuel);
}
};
연료(fuel)와 연비(power)를 랜덤 값으로 생성하여, 차를 이동시키는 car 객체를 만들어봅시다.
car.moved = 1000;
car.run();
car.fuel = 5000;
car.moved = 2000;
car.run();
랜덤 값을 생성하려고 했으나, 외부에서 의도적으로 랜덤값을 변경해 버리면 의도하지 않은 값이 나올 수 있죠. 즉, fuel, power, moved 등의 노출되면 안 될 변수들이 모두 public 한 상황입니다. 위의 변수들을 private 하게 변경해 볼게요.
let createCar = function() {
let fuel = Math.ceil(Math.random() * 10 + 10);
let power = Math.ceil(Math.random() * 3 + 2);
let moved = 0;
return {
get moved() {
return moved;
},
run: function() {
let km = Math.ceil(Math.random() * 6);
let wasteFuel = km / power;
if (fuel < wasteFuel) {
console.log('이동불가');
return;
}
fuel -= wasteFuel;
moved += km;
console.log(km + 'km 이동 (총 ' + this.moved + 'km), 남은 연로 : ' + fuel);
}
};
};
let c = createCar();
c.moved = 10000;
c.fuel = 200000;
c.run(); // 외부의 변경에 영향을 받지 않음
c.run = function() {
console.log('함수 변경')
};
c.run(); // run 메서드는 변경이 됨
car 객체를 만들어주는 함수를 사용해서 노출되면 안 될 변수(fuel, power, moved)를 변수로 생성하고, 노출할 run 메서드를 return 시켜주었어요. 외부에서 변수를 변경해 버리는 문제는 이제 발생하지 않지만, run 메서드 자체를 변경할 수 있다는 문제는 아직 남아있어요.
Object.freeze()
const obj = {
prop: 42
};
Object.freeze(obj);
obj.prop = 33;
// Throws an error in strict mode
console.log(obj.prop);
// Expected output: 42
자바스크립트에는 Object.freeze 메서드를 사용하면, 외부의 변경에도 변경되지 않도록 설정할 수 있습니다. freeze를 이용해서 run 메서드의 변경을 막을 수 있도록 변경해 볼게요.
let createCar = function() {
let fuel = Math.ceil(Math.random() * 10 + 10);
let power = Math.ceil(Math.random() * 3 + 2);
let moved = 0;
let publicMembers = { // return 할 public 정보들을 감싼다.
get moved() {
return moved;
},
run: function() {
let km = Math.ceil(Math.random() * 6);
let wasteFuel = km / power;
if (fuel < wasteFuel) {
console.log('이동불가');
return;
}
fuel -= wasteFuel;
moved += km;
console.log(km + 'km 이동 (총 ' + this.moved + 'km), 남은 연로 : ' + fuel);
}
};
Object.freeze(publicMembers); // 변경할 수 없게끔 freeze
return publicMembers; // return
};
let c = createCar();
c.run = function() {
console.log('함수 변경')
};
c.run(); // 외부의 영향 없이 정상 실행
다음과 같이 return 할 정보들을 하나의 객체로 감싸고, 그 객체를 Object.freeze 메서드를 통해 불변하도록 만든 후 return 해주면, 외부의 변경에도 변경되지 않고 안전한 코드로 만들 수 있어요.
클로저에 대한 포스팅은 아래를 참고해주세요.