자바 스크립트 객체의 속성 값에 대한 리스너
-
21-08-2019 - |
문제
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
개체는 다음과 같습니다.
- 그만큼
Proxy
객체는 이전 브라우저 (예 : IE11) 및 폴리 필 완전히 복제 할 수 없습니다Proxy
기능. - 프록시 객체는 특별한 개체 (예 :
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);
});
약속을 제거하고 대상 브라우저에서 약속이 지원되지 않는 경우에만 콜백을 유지하십시오.
중요한:
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)