본문 바로가기

3.구현/HTML5&Javascript

[javascript] 객체 변경 감지

들어기기

객체가 변경되었을때 특정 작업을 하는 경우가 의외로 많다. 객체의 변경 감지는 두가지 방법이 있다. 하나는 defineProperty이고 다른 하나는 Proxy이다.

작성자: ospace114@empal.com, http://ospace.tistory.com/

샘플객체

먼저 아래 객체가 있다고 하자.

let obj = { id: 1, name: 'foo', info: { type: 'object' } };

방법1: DefineProperty

먼저 defineProperty()를 사용해보자. defineProperty()에서 정적으로 value을 할당해서 사용하는 방법과 get과 set을 정의해서 사용하는 방법으로 나눌 수 있다. 여기에서는 value을 사용한 방법이 아니고 get과 set을 사용한 방법이 있다. 예를 들어 name 항목 변경을 감지하려면 다음과 같이 한다.

let value = obj.name;
Object.defineProperty(obj, 'name', {
    get() {
        return value
    },
    set(val) {
        value = val;
        console.log('changed value of name:', val);
    },
    enumerable: true
});

실행 후에 obj.name을 변경해보자.

obj.name = 'hi'
changed value of name: hi

이 방법은 기존 속성을 새로 정의하고 기존 속성 값을 별도로 관리해야 한다. 새로운 속성으로 정의했기 때문에 기존 값을 사용할 수 없게 된다.

평가

장점은 기본 코드 변경 없이 바로 정의해서 바로 사용할 수 있다. 또한 감지할 모든 속성을 일일히 정의해줘야 한다.

단점은 새로운 객체가 추가될 경우 감지할 수 없다.

방법2: Proxy

다음은 Proxy 객체를 사용한 방법이다. 이는 기존 객체에 래퍼 객체를 만들어서 모든 기능을 중간에 가로 채서 재정의한다. 실제 어떻게 사용하는지 살펴보자.

obj = new Proxy(obj, {
    set(target, prop, value) {
        target[prop] = value;
        console.log(`changed value of ${prop}:`, value);
        return true;
    },
    deleteProperty(target, prop) {
        delete target[prop];
        console.log(`deleted value of ${prop}`);
        return true;
    }
});

Proxy인 경우는 별도 속성 지정 없이 모든 속성에 대해서 감지한다. 단, 감지할 대상 속성은 깊이가 1인 경우만 해당한다. obj 객체에서 보면 info에 type은 변경감지 하지 못한다.

그리고 주의할 점은 Proxy에 의해 생성된 객체를 기존 객체 obj에 저장한다.

실행해보자.

obj.name = 'hi'
changed value of name: hi
delete obj.name
deleted value of name
console.log(obj.name)
undefined

평가

장점은 매번 속성별로 지정할 필요가 없고, 삭제까지 감지할 수 있다.

단점은 모든 깊이에 속성을 감지할 수 없고, 또한 생성된 프록시 객체를 기존 객체에 저장해야한다.

결론

기존 코드에 영향을 덜 미칠려면 defineProperty가 좋다. 만약, 완벽한 변경 감지를 하려면 Proxy을 사용해야 한다. 그러나 양쪽 모두 사용에 주의점이 있기에 상황에 맞게 판단해야 한다.

추가로 배열 객체인 경우는 push, pop, unshift, shift, splice등 내부 데이터에 영향을 미치는 메소드가 있다. defineProperty로 사용하는 경우 이런 메소드들도 고려해야 한다. Proxy을 사용할 경우는 그나마 덜하지만 복잡한 형태로 변경사항에 대한 정보가 발생한다. 직접 확인해보면 알게 된다. 모드 즐프 하세요. ospace.

참고

[1] Object.defineProperty(), https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

[2] Proxy, https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Proxy

반응형