Javascriptのドキュメントを調べてみると、Javascriptオブジェクトの次の2つの関数が面白そうだとわかりました。
.watch
-プロパティに値が割り当てられるのを監視し、それが発生すると関数を実行します。.unwatch
- watchメソッドで設定されたウォッチポイントを削除します。
使用例:
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を使用している場合を除く) 。
今は2018年で、この質問への回答は少し時代遅れです。
現在、オブジェクトに加えられた変更を監視(および傍受)するために プロキシ オブジェクトを使用できるようになりました。これは、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など)では使用できず、 polyfill はProxy
機能を完全に複製できません。Date
など)で常に期待どおりに動作するとは限りません。Proxy
オブジェクトは、プレーンオブジェクトまたは配列と組み合わせるのが最適です。ネストされたオブジェクトに加えられた変更を監視する必要がある場合は、-などの特殊なライブラリを使用する必要があります。 Observable Slim(私が作成したもの)。それはこのように動作します:
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}}]
チェックアウト - Object.defineProperty
および Object.prototype.\__defineGetter__
(または\__defineSetter__
)この機能がどこに向かっているのかを確認します。
Object.defineProperty
は、すぐにすべての最新のブラウザで利用できるようになるはずです。
Javascript Propery Events ライブラリをご覧ください。これは、私が最近作成した、いくつかのイベント呼び出し元でObject.defineProperty
を拡張する小さなライブラリです。 HTMLオブジェクトのon[event]
プロパティのように使用できるいくつかのon[event]
プロパティを追加します。また、失敗した場合に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);
});
promiseを削除し、ターゲットブラウザでPromiseがサポートされていない場合にのみコールバックを保持します
1)promiseを使用する際の非同期動作に注意してください。
2)Object.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)