How can I create a deep/recursive Proxy?
Specifically, I want to know whenever a property is set or modified anywhere in the object tree.
Here's what I've got so far:
function deepProxy(obj) {
return new Proxy(obj, {
set(target, property, value, receiver) {
console.log('set', property,'=', value);
if(typeof value === 'object') {
for(let k of Object.keys(value)) {
if(typeof value[k] === 'object') {
value[k] = deepProxy(value[k]);
}
}
value = deepProxy(value);
}
target[property] = value;
return true;
},
deleteProperty(target, property) {
if(Reflect.has(target, property)) {
let deleted = Reflect.deleteProperty(target, property);
if(deleted) {
console.log('delete', property);
}
return deleted;
}
return false;
}
});
}
And here's my test:
const proxy = deepProxy({});
const baz = {baz: 9, quux: {duck: 6}};
proxy.foo = 5;
proxy.bar = baz;
proxy.bar.baz = 10;
proxy.bar.quux.duck = 999;
baz.quux.duck = 777;
delete proxy.bar;
delete proxy.bar; // should not trigger notifcation -- property was already deleted
baz.quux.duck = 666; // should not trigger notification -- 'bar' was detached
console.log(proxy);
And the output:
set foo = 5
set bar = { baz: 9, quux: { duck: 6 } }
set baz = 10
set duck = 999
set duck = 777
delete bar
set duck = 666
{ foo: 5 }
As you can see, I've just about got it working, except baz.quux.duck = 666
is triggering the setter even though I've removed it from proxy
's object tree. Is there any way to de-proxify baz
after the property has been deleted?
You can configure proxies between various Trend Micro servers and services. In Deep Security Manager, go to Administration > System Settings > Proxies. In the Proxy Servers area, click New > New Proxy Server. In the Name and Description fields, enter a friendly name and description for your proxy.
This wikiHow will teach you how to create a proxy on Windows and Mac computers once your administrator or IT department has set up a proxy server. Open Settings. Press the Windows + I keys or open your Start menu and click the gear icon. Click Network & Internet. It's next to an icon of a gridded globe.
Select all the footage you want to create proxies for > right-click > and select ‘Proxy’ > ‘Create Proxies’. 2. In this new window, you can select the codec, either H.264 or QuickTime.
Creating proxy servers can increase your computer's security as well as save a company's bandwidth since they act as a mediator (middle-man) between your computer and the internet.
Here's a simpler one that does what I think you wanted.
This example allows you to get or set any properties deeply, and calls a change handler on any property (deep or not) to show that it works:
function createOnChangeProxy(onChange, target) {
return new Proxy(target, {
get(target, property) {
const item = target[property]
if (item && typeof item === 'object') return createOnChangeProxy(onChange, item)
return item
},
set(target, property, newValue) {
target[property] = newValue
onChange()
return true
},
})
}
let changeCount = 0
const o = createOnChangeProxy(() => changeCount++, {})
o.foo = 1
o.bar = 2
o.baz = {}
o.baz.lorem = true
o.baz.yeee = {}
o.baz.yeee.wooo = 12
console.log(changeCount === 6)
const proxy = createOnChangeProxy(() => console.log('change'), {})
const baz = {baz: 9, quux: {duck: 6}};
proxy.foo = 5;
proxy.bar = baz;
proxy.bar.baz = 10;
proxy.bar.quux.duck = 999;
baz.quux.duck = 777;
delete proxy.bar;
delete proxy.bar; // should not trigger notifcation -- property was already deleted
baz.quux.duck = 666; // should not trigger notification -- 'bar' was detached
console.log(proxy);
In the part that uses your code sample, there are no extra notifications like your comments wanted.
Fixed a bunch of bugs in my original question. I think this works now:
function createDeepProxy(target, handler) {
const preproxy = new WeakMap();
function makeHandler(path) {
return {
set(target, key, value, receiver) {
if (value != null && typeof value === 'object') {
value = proxify(value, [...path, key]);
}
target[key] = value;
if (handler.set) {
handler.set(target, [...path, key], value, receiver);
}
return true;
},
deleteProperty(target, key) {
if (Reflect.has(target, key)) {
unproxy(target, key);
let deleted = Reflect.deleteProperty(target, key);
if (deleted && handler.deleteProperty) {
handler.deleteProperty(target, [...path, key]);
}
return deleted;
}
return false;
}
}
}
function unproxy(obj, key) {
if (preproxy.has(obj[key])) {
// console.log('unproxy',key);
obj[key] = preproxy.get(obj[key]);
preproxy.delete(obj[key]);
}
for (let k of Object.keys(obj[key])) {
if (obj[key][k] != null && typeof obj[key][k] === 'object') {
unproxy(obj[key], k);
}
}
}
function proxify(obj, path) {
for (let key of Object.keys(obj)) {
if (obj[key] != null && typeof obj[key] === 'object') {
obj[key] = proxify(obj[key], [...path, key]);
}
}
let p = new Proxy(obj, makeHandler(path));
preproxy.set(p, obj);
return p;
}
return proxify(target, []);
}
let obj = {
foo: 'baz',
}
let proxied = createDeepProxy(obj, {
set(target, path, value, receiver) {
console.log('set', path.join('.'), '=', JSON.stringify(value));
},
deleteProperty(target, path) {
console.log('delete', path.join('.'));
}
});
proxied.foo = 'bar';
proxied.deep = {}
proxied.deep.blue = 'sea';
proxied.null = null;
delete proxied.foo;
delete proxied.deep; // triggers delete on 'deep' but not 'deep.blue'
You can assign full objects to properties and they'll get recursively proxified, and then when you delete them out of the proxied object they'll get deproxied so that you don't get notifications for objects that are no longer part of the object-graph.
I have no idea what'll happen if you create a circular linking. I don't recommend it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With