Is it possible to create an object container where changes can be tracked
Said object is a plex nested object of data. (pliant with JSON).
The wrapper allows you to get the object, and save changes, without specifically stating what the changes are
Does there exist a design pattern for this kind of encapsulation
Deep cloning is not an option since I'm trying to write a wrapper like this to avoid doing just that.
The solution of serialization should only be considered if there are no other solutions.
An example of use would be
var foo = state.get();
// change state
state.update(); // or state.save();
client.tell(state.recentChange());
A jsfiddle snippet might help : /
It seems like implementing an internal hash to keep track of changes is the best option.
[Edit]
To clarify this is actaully done on node.js on the server. The only thing that changes is that the solution can be specific to the V8 implementation.
Is it possible to create an object container where changes can be tracked
Said object is a plex nested object of data. (pliant with JSON).
The wrapper allows you to get the object, and save changes, without specifically stating what the changes are
Does there exist a design pattern for this kind of encapsulation
Deep cloning is not an option since I'm trying to write a wrapper like this to avoid doing just that.
The solution of serialization should only be considered if there are no other solutions.
An example of use would be
var foo = state.get();
// change state
state.update(); // or state.save();
client.tell(state.recentChange());
A jsfiddle snippet might help : http://jsfiddle/Raynos/kzKEp/
It seems like implementing an internal hash to keep track of changes is the best option.
[Edit]
To clarify this is actaully done on node.js on the server. The only thing that changes is that the solution can be specific to the V8 implementation.
Share Improve this question edited Jan 7, 2011 at 9:52 Raynos asked Jan 6, 2011 at 23:30 RaynosRaynos 170k57 gold badges357 silver badges398 bronze badges 4- This shouldn't be a very big deal. But Could you be more specific about the format of the showChanges function? For instance if a string is changed from "Joe" to "Ann" how would you like to display that? I found it odd that you said foo was changed by 1 ... rather than saying foo was changed from 10 to 1 (or whatever the start value of foo was). – Zevan Commented Jan 7, 2011 at 0:05
- @Zevan the format is irrelevant. I'm more interested in how it can be tracked internally. Any format where it state name was x but is now y is sufficient – Raynos Commented Jan 7, 2011 at 0:12
- what about for something like this : {person:{name:"Joe", hobby:"Guitar}} basically a nested object. That is, would you say that person -> name has changed or that name has changed? – Zevan Commented Jan 7, 2011 at 0:30
- @Zevan you say something unambigious. What it is doesnt matter it merely needs to indicate unambigiously exactly what the change was – Raynos Commented Jan 7, 2011 at 9:09
5 Answers
Reset to default 3Stripping away the javascript aspect of this problem, there are only three ways to know if something has changed:
- Keep a copy or representation to pare with.
- Observe the change itself happening in-transit.
- Be notified of the change.
Now take these concepts back to javascript, and you have the following patterns:
- Copy: either a deep clone, full serialization, or a hash.
- Observe: force the use of a setter, or tap into the javascript engine (not very applicable)
- Notify: modifying the code that makes the changes to publish events (again, not very applicable).
Seeing as you've ruled out a deep clone and the use of setters, I think your only option is some form of serialisation... see a hash implementation here.
You'll have to wrap all your nested objects with a class that reports you when something changes. The thing is, if you put an observer only in the first level object, you'll only receive notifications for the properties contained in this object.
For example, imagine you have this object:
var obj = new WrappedObject({
property1: {
property1a: "foo",
property1b: 20,
}
})
If you don't wrap the object contained in porperty1, you'll only receive a "get" event for property1
, and just that, because when someone runs obj.property1.property1a = "bar"
the only interaction that you'll have with obj, will be when it asks for the reference of the object contained in property1
, and the modification will happen in an unobserved object.
The best approach I can imagine, is iterating over all the properties when you wrap the first object, and constructing recursively a wrapper object for every typeOf(property) == "Object"
.
I hope my understanding of your question was right. Sorry if not! It's my first answer here :$.
There's something called reactive programming that kind of resembles what you ask about, but its more involved and would probably be overkill.
It seems like you would like to keep a history of values, correct? This shouldn't be too hard as long as you restrit changes to a setter function. Of course, this is more difficult in javascript than it is in some other languages. Real private fields demand some clever use of closures.
Assuming you can do all of that, just write something like this into the setter.
function setVal(x)
{
history.push(value);
value = x;
}
You can use the solution that processing.js uses. Write the script that accesses the wrapped object normally...
var foo = state.get();
foo.bar = "baz";
state.update();
client.tell(state.recentChange());
...but in the browser (or on the server if loading speed is important) before it runs, parse the code and convert it to this,
var foo = state.get();
state.set(foo, "bar", "baz");
state.update();
client.tell(state.recentChange());
This could also be used to do other useful things, like operator overloading:
// Before conversion
var a=new Vector(), b=new Vector();
return a + b * 3;
// After conversion
var a=new Vector(), b=new Vector();
return Vector.add(a,Vector.multiply(b,3));
It would appear that node-proxy
implements a way of doing this by wrapping a proxy around the entire object. I'll look into more detail as to how it works.
https://github./samshull/node-proxy