Here's a simple backdraftjs component with watchables:
class TestComponent extends Component.withWatchables('veg') {
constructor( kwargs ) {
super( kwargs );
// 'veg' is a watchable
this._veg = 'carrot';
console.log(this.veg); // 'carrot'
// 'fruit' is not a watchable
this._fruit = 'banana';
console.log(this.fruit); // undefined
}
bdElements() {
return e.div('hi there');
}
}
Why am I allowed to set this.veg
by setting this._veg
? What's the purpose of that, and what's the difference if I just set it using this.veg = whatever
?
This is an intentional implementation technique employed by the backdraft framework. It follows the philosophy of trying to balance the equities of
The key ideas behind a watchable are three:
All that said, a watchable variable must be actually stored somewhere. There are lots of options available to accomplish that...from closures to Proxy.
Proxy works great...if you have a browser that supports it. This version of Backdraft is now approaching 5 years old (and it original version is now more than 15 years old). Five years ago, Proxy wasn't available on many browsers important to commercial products; many businesses must still support browsers that do not support Proxy today.
Other techniques...closures, closures with maps, and so on...add a fair amount of complexity for questionable return; ergo, they were not selected.
So the technique chosen is trivial: for a watchable property
x
._x
.x
that simply returns_x
.x
that===
); if not, then no-op, otherwise..._x
to mutated valueThis fulfills the promise of a watchable.
It also exposes
_x
, and if the user of the class instance insists on breaking the abstraction barrier, then things will not work as expected (setting_x
directly won't cause the normal watchable mutation machinery to fire). But the only way to do that is to explicitly writemyInstance._x = someNewValue
...which is pretty hard to do by accident. Finally note that this is no different...no more or less safe than breaking the private barrier in even strongly-typed languages like C++ by typecasting. Lastly, for the really unusual situation where the programmer really wants to mutate_x
directly, it is possible.I think all these things put together fairly balance the equities considered.