문제

JavaScript 문서를 살펴보면 JavaScript 객체의 다음 두 기능이 흥미로워 보입니다.

.watch - 속성이 값을 할당하고 발생할 때 기능을 실행합니다.
.unwatch - 시계 메소드가있는 워치 포인트를 제거합니다.

샘플 사용 :

o = { p: 1 };
o.watch("p", function (id,oldval,newval) {
    console.log("o." + id + " changed from " + oldval + " to " + newval)
    return newval;
});

"P"의 속성 값을 변경할 때 마다이 함수가 트리거됩니다.

o.p = 2;   //logs: "o.p changed from 1 to 2"

나는 지난 몇 년 동안 JavaScript를 연구하고 있으며 이러한 기능을 사용한 적이 없습니다.
누군가이 기능이 유용한 곳에서 좋은 사용 사례를 던질 수 있습니까?

도움이 되었습니까?

해결책

시계가 실제로 설계된 것은 속성 값의 검증입니다. 예를 들어 무언가가 정수임을 확인할 수 있습니다.

obj.watch('count', function(id, oldval, newval) {
    var val = parseInt(newval, 10);
    if(isNaN(val)) return oldval;
    return val;
});

문자열 길이를 검증하는 데 사용할 수 있습니다.

obj.watch('name', function(id, oldval, newval) {
    return newval.substr(0, 20);
});

그러나 이들은 Spidermonkey JavaScript 엔진의 최신 버전에서만 사용할 수 있습니다. Jaxer를 사용하거나 Spidermonkey 엔진을 포함시키고 있지만 아직 브라우저에서는 사용할 수없는 경우 (FF3를 사용하지 않는 한).

다른 팁

체크 아웃 Object.defineProperty 그리고Object.prototype.\__defineGetter__ (또는 \__defineSetter__ )이 기능이 어디로 향하고 있는지 확인합니다.

Object.defineProperty 곧 모든 현대식 브라우저에서 사용할 수 있어야합니다.

지금은 2018 년 이며이 질문에 대한 답변은 약간 구식입니다.

  • 객체. 워치 그리고 Object.observe 둘 다 더 이상 사용되지 않으며 사용해서는 안됩니다.
  • onpropertyChange 일부 버전의 IE에서만 작동하는 DOM 요소 이벤트 핸들러입니다.
  • Object.DefineProperty 객체 속성을 불변으로 만들 수 있으므로 변경 시도를 감지 할 수 있지만 변경 사항도 차단할 수 있습니다.
  • 세터와 getters 정의 작동하지만 많은 설정 코드가 필요하며 새 속성을 삭제하거나 생성 해야하는 경우 잘 작동하지 않습니다.

오늘, 이제 사용할 수 있습니다 대리 물체 객체에 대한 변경을 모니터링하고 가로 채기 위해. OP가하려는 일을위한 목적입니다. 기본 예는 다음과 같습니다.

var targetObj = {};
var targetProxy = new Proxy(targetObj, {
  set: function (target, key, value) {
      console.log(`${key} set to ${value}`);
      target[key] = value;
      return true;
  }
});

targetProxy.hello_world = "test"; // console: 'hello_world set to test'

유일한 단점 Proxy 개체는 다음과 같습니다.

  1. 그만큼 Proxy 객체는 이전 브라우저 (예 : IE11) 및 폴리 필 완전히 복제 할 수 없습니다 Proxy 기능.
  2. 프록시 객체는 특별한 개체 (예 : Date) - Proxy 객체는 일반 객체 나 배열과 가장 잘 어울립니다.

a에 대한 변경 사항을 관찰 해야하는 경우 중첩 된 물체, 그런 다음 다음과 같은 특수 라이브러리를 사용해야합니다. 관찰 가능한 슬림 (내가 저술 한). 다음과 같이 작동합니다.

var test = {testing:{}};
var p = ObservableSlim.create(test, true, function(changes) {
    console.log(JSON.stringify(changes));
});

p.testing.blah = 42; // console:  [{"type":"add","target":{"blah":42},"property":"blah","newValue":42,"currentPath":"testing.blah",jsonPointer:"/testing/blah","proxy":{"blah":42}}]

당신은 그것을 볼 수 있습니다 JavaScript Propery 이벤트 도서관. 작은 라이브러리가 확장됩니다 Object.defineProperty 내가 최근에 만든 일부 이벤트 발신자와 함께. 몇 가지를 추가합니다 on[event] 처럼 사용할 수있는 속성 on[event] HTML-Objects의 특성. 또한 간단한 유형 확인이있어 onerror 실패한 경우 이벤트.

코드를 가져 오면 다음과 같은 결과가 나옵니다.

var o = {}
Object.defineProperty(o, "p", {
    value:1,
    writable:true,
    onchange:function(e){
        console.log("o." + e.target + " changed from " + e.previousValue + " to " + e.returnValue);
    }
})

setInterval을 사용할 수 있습니다

Object.prototype.startWatch = function (onWatch) {

    var self = this;

    if (!self.watchTask) {
        self.oldValues = [];

        for (var propName in self) {
            self.oldValues[propName] = self[propName];
        }


        self.watchTask = setInterval(function () {
            for (var propName in self) {
                var propValue = self[propName];
                if (typeof (propValue) != 'function') {


                    var oldValue = self.oldValues[propName];

                    if (propValue != oldValue) {
                        self.oldValues[propName] = propValue;

                        onWatch({ obj: self, propName: propName, oldValue: oldValue, newValue: propValue });

                    }

                }
            }
        }, 1);
    }



}

var o = { a: 1, b: 2 };

o.startWatch(function (e) {
    console.log("property changed: " + e.propName);
    console.log("old value: " + e.oldValue);
    console.log("new value: " + e.newValue);
});

Object.DefineProperty

약속하다

약속을 제거하고 대상 브라우저에서 약속이 지원되지 않는 경우에만 콜백을 유지하십시오.

중요한:

1) 약속 사용에 대한 비동기 동작에주의하십시오.

2) Objebs.DefineProperty는 콜백을 트리거하지 않으며 연산자를 할당하는 것만 할당합니다.

Object.onPropertySet = function onPropertySet(obj, prop, ...callback_or_once){
    let callback, once;
    for(let arg of callback_or_once){
        switch(typeof arg){
        case "function": callback = arg; break;
        case "boolean": once = arg; break;
        }
    }


    let inner_value = obj[prop];
    let p = new Promise(resolve => Object.defineProperty(obj, prop, {
        configurable: true,
        // enumerable: true,
        get(){ return inner_value; },
        set(v){
            inner_value = v;
            if(once){
                Object.defineProperty(obj, prop, {
                    configurable: true,
                    // enumerable: true,
                    value: v,
                    writable: true,
                });
            }
            (callback || resolve)(v);
        }
    }));
    if(!callback) return p;
};

// usage
let a = {};
function sayHiValue(v){ console.log(`Hi "${v}"`); return v; }

// do
Object.onPropertySet(a, "b", sayHiValue);
a.b = 2; // Hi "2"
a.b = 5; // Hi "5"

// or
Object.onPropertySet(a, "c", true).then(sayHiValue).then(v => {
    console.log(a.c); // 4 // because a.c is set immediatly after a.c = 3
    console.log(v); // 3 // very important: v != a.c if a.c is reassigned immediatly
    a.c = 2; // property "c" of object "a" is re-assignable by '=' operator
    console.log(a.c === 2); // true
});
a.c = 3; // Hi "3"
a.c = 4; // (Nothing)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top