본문으로 바로가기

객체지향 언어에서의 멤버에 대한 접근 제어

일반 객체지향 언어에서는 멤버에 대한 접근을 제어하기 위해 public, private 같은 한정자를 제공합니다.

그러나 자바스크립트에서는 멤버에 대한 접근 제어 및 정보 은닉을 위한 특별한 키워드를 언어 차원에서 제공하지 않습니다.

자바스크립트에서의 공개 속성은 "값을 직접 가지고 있는 변수"와 같습니다.

따라서 객체의 내부 상태를 속성을 통해 그대로 노출하는 것입니다.

이것은 "정보 은닉"이 되지 않는다는 의미입니다.

때로는 변수의 값을 외부에 노출시키기도 하지만 값을 외부에서 직접 접근하지 못하도록 비공개 멤버(private member)를 만들고 싶은 경우도 있습니다.

하지만 자바스크립트에서는 이러한 비공개 멤버를 만드는 방법을 지원하지 않으므로 개발자가 이를 직접 구현해야 합니다.

여기서는 접근 제어를 위한 특별한 패턴 2가지를 소개합니다.





비공개 멤버 구현

비공개 멤버를 구현하는 첫 번째 방법을 소개합니다.

함수의 지역 변수는 외부에서 접근할 수 없는 비공개 변수이므로 이러한 지역 변수가 객체의 상태값을 가지고 있으면 됩니다.

문제는 공개 멤버가 비공개 변수에 직접 접근할 수 없다는 것입니다.

따라서 공개 멤버는 내부 변수에 접근할 수 있는 내부 함수를 두고서 이 함수를 통해 내부 상태값에 접근해야 합니다.


이를 정리하면 이렇습니다.

객체의 상태값으로 내부의 지역 변수를 사용하고 외부의 접근 메서드로는 공개 메서드를 사용하되, 공개 메서드는 지역 변수에 접근하는 내부 함수를 정의해서 사용한다는 것입니다.

즉, 상태값과 공개된 외부 메서드 사이에 내부 함수가 존재하는 구조가 됩니다.


내부 변수(상태값) ↔ 내부 함수 ↔ 공개 메서드


다음은 공개된 속성을 이렇게 내부 변수와 그에 대응하는 전용 함수를 사용하는 방식으로 작성한 예제입니다.

javascript
function A() {
    // 내부 지역 변수(상태값)
    var _localX = 7;

    // 공개 접근 메서드
    this.getX = function() {
        return _localX;
    };

    // 10보다 작은 수만 속성값으로 입력받는다.
    this.setX = function (x) {
        if( x < 10 ) {
            _localX = x;
        }
            return _localX;
    }
}

지역 변수 _localX 의 읽기, 쓰기 전용의 공개 메서드인 getX, setX 를 정의했습니다.

getX, setX에서는 다시 지역변수에 접근하기 위해 익명함수를 내부에서 사용하고 있습니다.


이처럼 직접 속성의 상태값에 접근하지 않고 내부의 정의된 함수를 통해 접근하는 구조가 되면 내부 상태값을 반환할 때는 그 값을 필요한 대로 가공해서 건네줄 수 있고, 값을 할당할 때도 입력받은 값을 가공하거나 유효성 검사 등을 수행한 후 상태값을 변경할 수 있습니다.

위 코드에서는 내부 상태 변수에 할당될 값은 10보다 작아야 한다는 조건을 지정했습니다.


이제 다음과 같이 A의 객체를 생성한 후 공개 메서드를 통해 값에 접근할 수 있습니다.

javascript
function A() {
    // 내부 지역 변수(상태값)
    var _localX = 7;

    // 공개 접근 메서드
    this.getX = function() {
        return _localX;
    };

    // 10보다 작은 수만 속성값으로 입력받는다.
    this.setX = function (x) {
        if( x < 10 ) {
            _localX = x;
        }
        return _localX;
    };
}

var obj = new A();
var x = obj.getX();
console.log(x); // _localX의 값인 7을 출력
console.log(obj.setX(8)); // localX 에 8을 설정하여 8을 출력함
console.log(obj.setX(11)); // 8을 출력

obj.setX(11) 은 내부 조건에 부합되지 않아 11이 할당되지 않고 앞서 할당된 obj.setX(8)의 값인 8이 반환됩니다.




클로저 인스턴스

이제 비공개 멤버와 공개 멤버를 가진 객체를 구현하는 패턴화된 기법을 소개합니다.

이 기법을 이용하면 자바스크립트에서도 일반 객체지향 언어에서의 객체와 유사한 구조의 객체를 만들어낼 수 있습니다.


자바스크립트 클로저는 "비공개 변수를 가질 수 있는 함수 인스턴스의 생성자"입니다.

만약 클로저가 익숙치 않다면 클로저를 이해한 후 읽어보시길 바랍니다.

여기서는 비공개 멤버를 가진 객체를 생성하는 데 클로저를 사용할 것입니다.


비공개 객체 정의는 비공개 멤버, 공개 멤버로 설계할 수 있습니다.

다음과 같이 공개, 비공개 멤버 구조를 지닌 객체를 만들어 낼 수 있는 outer 라는 클로저를 정의해 봅니다.

javascript
function outer() {
    // 비공개 멤버
    var _x = 0;

    function _private01() {
        return ++_x;
    }

    function _private02() {
        return (_x += 2);
    }

    // 공개 멤버(반환된 객체를 통해 외부에 공개된다)
    return {
        public01 : _private01,
        public02 : _private02
    };
}

_private01(), _private02()는 내부 변수 _x를 각각 1,2씩 증가시키는 내부 함수이고, 이 내부 함수를 각각 호출하는 함수 public01, public02 는 return 문에서 반환한 객체를 통해 외부에 공개하고 있습니다.


return 문으로 반환된 객체가 외부에 나가서 사라지지 않는 한 내부의 _x 값도 계속 유지됩니다.

그리고 클로저인 outer를 호출할 때마다 반환되는 객체별로 내부 변수 _x가 초기화됩니다.


다음은 앞에서 정의한 outer를 호출해 객체를 생성하고 실행하는 예제 코드입니다.

javascript
var obj1 = outer(); // 인스턴스 obj1 생성
console.log(obj1.public01()); // 1 출력
console.log(obj1.public02()); // 3 출력

var obj2 = outer(); // 인스턴스 obj2 생성 (새롭게 반환되는 인스턴스로 _x가 초기화된다)
console.log(obj2.public01()); // 1 출력
console.log(obj2.public02()); // 3 출력

outer()를 호출해서 생성된 객체를 obj1에 할당합니다.

public01을 호출해서 값을 1 증가시키면 public02가 호출될 때 이전에 증가된 값이 유지되어 두 번째 호출의 시작값이 됩니다.

outer 함수 호출이 종료되더라도 내부 변수 스코프 객체는 그대로 유지되는 클로저의 속성을 그대로 이용하고 있습니다.


다시 한번 outer()를 호출해서 새로운 인스턴스를 obj2에 할당한 후 public01, public02를 호출해서 결과를 보면 내부 변수 _x가 새롭게 초기화됐다는 사실로 앞의 클로저와는 다른 닫힌 환경을 가진 새로운 인스턴스가 생성됐음을 알 수 있습니다.


클로저를 호출하면 단순히 객체가 반환되는 것이 아닙니다. 객체와 함께 그것과 연결된 닫힌 공간이 함께 반환되는 것입니다.

그리고 그 닫힌 공간에 내부 변수가 존재합니다.


클래스와 new를 사용해 여러 개의 닫혀진 공간을 가진 인스턴스를 만들어 내듯이 클로저와 ()를 이용(함수 호출)하면 닫힌 공간을 가진 인스턴스를 여러 개 반복해서 만들어 낼 수 있습니다.

즉, 클로저는 클래스와 유사한 존재로 볼 수 있다는 것입니다.


위의 outer 함수를 이용한 클로저 인스턴스는 obj1, obj2에 독립적인 변수 공간을 가진 인스턴스를 생성해 낸 것입니다.

그래서 클로저를 통한 생성은 개념적으로는 클래스를 이용한 생성과 거의 유사합니다.


클로저를 호출할 때마다 새로운 인스턴스가 생성된다.

새로운 클로저 인스턴스는 내부 상태가 초기화된 새로운 닫힌 환경을 가진다.



Jaehee's WebClub