DEV Community

Cover image for Detect object changes with JavaScript Proxy

Detect object changes with JavaScript Proxy

Chris Bongers on July 10, 2022

Let's say we have an object for our users. How can we detect when a property changes? const user = { firstName: 'Chris', lastName: 'Bongers'...
Collapse
 
yuridevat profile image
Julia πŸ‘©πŸ»β€πŸ’» GDE

Thank you for the great Proxy Series coming out now.

What I am always struggling with is (with JavaScript), that I am not able to get when I would use it. I would be happy if there would be a styled frontend to it, which would finally help me getting a deeper understanding of JavaScript.

Like, do you use it when I have an account on a webapp where I had to fill out my personal data, saved it, and realized that I got something wrong? Like in a CRUD App?

This should not be a criticism to your article because in fact it is really good explained but more of a "sigh" again to myself that I am not able to get a deeper understanding of JavaScript because without the frontend I cannot quite understand. πŸ˜…

Collapse
 
dailydevtips1 profile image
Chris Bongers

Hi Julia,

This is indeed always a tricky question and like @lexlohr mentions: it depends.
When it comes to things like Proxy trust me, you are very unlikely to need them.
And when you do, you'll know it.

I think often there are so many ways to do the same things in JavaScript that there is no real right or wrong.
However there are always optimisations to achieve.
Something of which Alex again is super good at.

I really wish there was some kind of visual representation on when to use what, but at least to me it's not as simple to explain it in such way.

I'll provide some more details on when I used this Proxy for the first time in tomorrows article, hope that helps a bit.

Collapse
 
yuridevat profile image
Julia πŸ‘©πŸ»β€πŸ’» GDE • Edited

Thank you so much for your answer, Chris. I really appreciate it.

Collapse
 
lexlohr profile image
Alex Lohr

If I understand you correctly, you are asking when to use which solution. Unfortunately, as so often in development, the answer is: it depends.

A simple form to get personal data would better solved as a static page with a server backend, since for security reasons, you need to validate the data on the server in any case. If you got that, you can progressively enhance with JS. However, if that form is part of an app that requires JS anyway, you can write it as part of that app (just don't forget the server validation).

That being said, what you miss is not understanding of JS, but understanding of development patterns.

Collapse
 
peerreynders profile image
peerreynders • Edited

After doing some digging I came across Manuel Matuzović's article How To Build A Progressively Enhanced, Accessible, Filterable And Paginated List.

Unfortunately it uses Alpine.js rather than vanilla JS which would have been more instructive but given that it also provides a github repo and codepen it might be a good candidate for "poking and prodding" to figure out how things work (i.e. don't read too much into the particular technologies that go into this example).

Summarizing progressive enhancement:

  • Content is the foundation
  • Markup is an enhancement (HTML)
  • Visual Design is an enhancement (CSS)
  • Interaction is an enhancement (JS)

This is part of the web's approach to resilience; fundamentally JavaScript is the least important layer of the web.

This realization came after it became clear that "graceful degradation" does not work.

However about the same time (~2010) another architectural style emerged: the Single Page Application (SPA).

SPAs turned the web on its head; JavaScript was no longer the least important aspect but JavaScript became the most important aspect because JavaScript became responsible for everything (completely sidelining the browser's capabilities to parse HTML and process CSS even before any JavaScript started executing).

That situation has contributed to a lot of the confusion around the role of JavaScript on the web.

It's only recently that the industry has started paying attention to progressive enhancement again, due to the renewed interest in server-side rendering.

Collapse
 
arthurdenner profile image
Arthur Denner

From a recent project: we had an object passed to N "loader functions" depending on the URL requested. We changed the signature of these loader functions but we couldn't remove the object while some of these loader functions used it.

I used a Proxy to detect and report access and calls to properties/methods on the deprecated object. This way we could track who, where and what was being accessed/called and act accordingly.

Like others said, it's good to understand Proxies, they are very powerful. It was the first time I used them on a production project but as soon as I got the requirement, I knew a Proxy would be a good fit.

Collapse
 
lexlohr profile image
Alex Lohr

Nice write-up, especially the part about deep proxies. However, it would have been nice to show how proxies merely wrap objects in setters/getters, which you can do manually in order to increase performance:

const _user = {
  firstName: 'Chris',
  lastName: 'Bongers',
  age: 10,
};
const user = {};
Object.defineProperties(
  user,
  Object.getOwnPropertyNames(_user)
    .reduce((properties, prop) => {
      properties[prop] = {
        get: () => _user[prop],
        set: (value) => {
          console.log(`changed ${prop} from ${_user[prop]} to ${value}`;
          _user[prop] = value;
          return value;
        }
      };
      return properties;
    }, {})
);
Enter fullscreen mode Exit fullscreen mode

However, that only intercepts uses of existing properties.

Collapse
 
dailydevtips1 profile image
Chris Bongers

Hey Alex,

I'm aware of the underlying wrapping, but yet thought this would even confuse people more.
The one thing i'm not really aware of, how much performance loss are we talking about when comparing proxy to its native alter ego?

Collapse
 
lexlohr profile image
Alex Lohr

It won't matter below a few thousands of accesses per second, so it will probably be more relevant to benchmarking than to actual applications. Still, I have encountered some real-life applications that would have done better in terms of performance without extensive proxying.

Thread Thread
 
dailydevtips1 profile image
Chris Bongers

Makes sense, thanks for that info 🀘

Thread Thread
 
jsagon profile image
Jhonatan S. GonΓ§alves • Edited

Hi, Chris and Alex

I was curious about the performance difference, and I tried the jsbench to see the result. In every test the Proxy is the fastest one.

Image description

Thread Thread
 
lexlohr profile image
Alex Lohr

The setup performance in this case is obviously better for proxy, since it's native. I was talking about access.

 
peerreynders profile image
peerreynders • Edited

MobX, SolidJS Stores (not to be confused with signals) and Vue use Proxies.


Exploring the state of reactivity patterns inΒ 2020 - JavaScript inDepth

Exploring the trend that has already changed the shape of front end UI development regardless of framework.

favicon indepth.dev

GitHub logo WebReflection / proxy-pants

Secured and reliable Proxy based utilities for more or less common tasks.

proxy-pants

build status Coverage Status CSP strict

Social Media Photo by lan deng on Unsplash

Secured and reliable Proxy based utilities for more or less common tasks:

  • accessor to trap one or more accessors for any object
  • applier & caller to trap any borrowed callback/utility without needing to use .call or .apply to pass the context
  • bound to bind one or more methods all at once
  • bread & crumbs to track operations through paths (i.e. a.b.c.d) and namespaces
  • cache to compute once any accessed property through a proxied, and secured, map
  • chain to trap once all inherited descriptors down the prototypal chain and automatically ensure the right accessor or method
  • dsm to virtually trap dataset / *set accessors as DOMStringMap like references per each element. Please note this utility is not secured
  • extender to extend any object through weakly referenced behaviors, providing a new way to deal with state machines too, through the following features
    • …
Collapse
 
omarbenmegdoul profile image
Omar Benmegdoul

Why?

Collapse
 
dailydevtips1 profile image
Chris Bongers

Missing a bit of context here.
I use it outside a library or framework.

It's a valid option when you need it.
Basically mocking existing methods, for very specific use-cases.

However. agree only use this when you have no other alternative.

 
omarbenmegdoul profile image
Omar Benmegdoul

Speaking of which, is this how react state is implemented?