If I have a class like:
class Myclass {
constructor(){
this.a = [];
this.sum = 0;
}
update(){
this.sum = this.a.reduce((a, b) => a + b, 0)
}
}
I instantiate the class:
myClass = new Myclass();
I append a number to the a
attribute
myClass.a.push(1);
myClass.a.push(2);
How can I call the update method every time the a
attribute is modified? In other words, how can I trigger a callback when an object attribute is altered?
If I have a class like:
class Myclass {
constructor(){
this.a = [];
this.sum = 0;
}
update(){
this.sum = this.a.reduce((a, b) => a + b, 0)
}
}
I instantiate the class:
myClass = new Myclass();
I append a number to the a
attribute
myClass.a.push(1);
myClass.a.push(2);
How can I call the update method every time the a
attribute is modified? In other words, how can I trigger a callback when an object attribute is altered?
-
1
In general, you could use a getter/setter for this, but the
.a
attribute is not altered, there is no assignment to it. Rather, the array that the property holds is mutated, and detecting that is a bit more plicated. – Bergi Commented Apr 27, 2020 at 12:23
4 Answers
Reset to default 7Add method for pushing new items to the a
array, e.g:
class Myclass {
constructor(){
this.a = [];
this.sum = 0;
}
update(){
this.sum = this.a.reduce((a, b) => a + b, 0)
}
pushItem(val) {
this.a.push(val);
this.update();
}
}
myClass = new Myclass();
myClass.pushItem(1);
myClass.pushItem(2);
console.log(myClass.sum);
One way is to extend Array
and shadow the push
method.
class MyArray extends Array{
constructor(ref){
super();
this.ref = ref
}
push(value){
super.push(value)
this.ref.update()
console.log("called")
}
}
class Myclass {
constructor(){
this.a = new MyArray(this);
this.sum = 0;
}
update(){
this.sum = this.a.reduce((a, b) => a + b, 0)
}
}
let myClass = new Myclass()
myClass.a.push(1);
myClass.a.push(2);
console.log(myClass.sum)
P.S:- Certainly not a good idea to call the callback on each insertion if you're not using the sum value after insertion.
In other words, how can I trigger a callback when an object attribute is altered?
This is a general solution to the above question. If you need a use-case specific solution for the a
array only, please ignore this.
Check ES6 Proxies for something more powerful than simple getters/setters for get/set interception. You may want to recursively wrap with Proxies since you have a nested data structure. Something like this:
function wrapWithProxyCallback(obj, callback) {
return new Proxy(obj, {
get (target, key, receiver) {
const result = Reflect.get(target, key, receiver)
// wraps nested data with Proxy
if (typeof result === 'object' && result !== null) {
return wrapWithProxyCallback(result, callback)
}
return result
},
set (target, key, value, receiver) {
// calls callback on every set operation
callback(target, key, value /* and whatever else you need */)
return Reflect.set(target, key, value, receiver)
}
})
}
And use it like:
const wrappedClass = wrapWithCallback(
myClass,
(target, key) => console.log(target[key])
)
// this will call the above callback
wrappedClass.a.push(1);
This is a bit naive but a good general starting point. You may want to check if nested data is already wrapped by Proxies for example.
What you want to do is probably nicely aligning with transparent reactivity (I would have to see your callback's content to be sure about this though.) I think you should check out mobx or @nx-js/observer-util (the latter is authored by me) for production-ready boxed solutions.
Edit: My first example triggered the callback on get operations, I corrected that to trigger on set operations.
Maybe by organizing the object as
class Myclass {
constructor(){
this.a = [];
}
get sum(){
return this.a.reduce((a, b) => a + b, 0)
}
}
If I'm not mistaken calling myClass.sum
will return the total of values in the array held under the a
attribute.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744726411a4590207.html
评论列表(0条)