Closed ivospinheiro closed 5 years ago
So the problem with the following:
var Todo = DefineMap.extend("Todo",{
id: {identity: true, type: "number"},
task: "string",
get _serialize() {
return this.serialize();
}
});
const TodoList = DefineList.extend({
"#": Todo
});
superMap({
Map: Todo,
List: TodoList,
url: "/services/todos",
name: "todo"
});
queues.log();
var t1 = new Todo({ id: 1, task: "Do something 1" });
t1.on("_serialize", () => {});
We are listening to can.onInstanceBoundChange
on the Todo
type. This works by making all
instances, when first bound, look to dispatch this sort of event on their constructor.
When _serialize
is bound, that will call getOwnEnumerableKeys
which looks like:
ObservationRecorder.add(this, 'can.keys');
ObservationRecorder.add(Object.getPrototypeOf(this), 'can.keys');
This will listen to can.keys
on both the t1
instance and the Todo.prototype
.
Listening to can.keys
on Todo.prototype
will be the first "listener" on Todo.prototype
. This will try to dispatch the can.dispatchInstanceBoundChange
on the .constructor
:
// can-event-queue
obj.constructor[dispatchBoundChangeSymbol](obj, true)
As Todo.prototype.constructor
is Todo
, this will effectively dispatch a can.onInstanceBoundChange
event on Todo
with Todo.prototype
as the instance.
As it looks like an instance
is bound, we will try to read it's .id
property. To read the .id
property, _data
is read. As the instance is Todo.prototype
, this will invoke the lazy getter for all future instances.
The most obvious solution is to prevent binding changes on the prototype from dispatching can.onInstanceBoundChange
events. I think we should check if obj.constructor.prototype === obj
. If this is the case, we should not dispatch.
Please check the behavior of this sample code: https://codepen.io/anon/pen/JmEdZR?editors=1011
The expected console output should be:
But the current result is:
Apparently it is somehow related with constructorStore behavior.