Question

I'm seeing strange behaviour using JSON.stringify against a subclassed model in Spine, and I'm hoping someone can help!

Here's a simplified excerpt from some code that we've got on one of our projects:

define([
    "jquery",
    "underscore"
],

function ($, _) {
    var SuperClass = Spine.Model.sub();
    SuperClass.configure("SuperClass", "SuperClassProperty");

    var SubClass = SuperClass.sub();
    SubClass.configure("SubClass", "SubClassProperty");

    var instance = new SubClass({ SuperClassProperty: "Super", SubClassProperty: "Sub" });
    console.log(instance);

    var json = JSON.stringify(instance);
    console.log(json);
});

The "console.log(instance)" is printing out exactly what I would expect in this scenario:

result
    SubClassProperty: "Sub"
    SuperClassProperty: "Super"
    cid: "c-0"
    __proto__: ctor

However, when I use JSON.stringify against the instance, this is all that I am returned:

{"SubClassProperty":"Sub"} 

Why doesn't the SuperClassProperty get included in the stringify?

I've ruled out a problem with the JSON.stringify method by forcing JSON2 to override Chrome's native JSON object; both implementations yield the same result. It looks like stringify will delegate to the "toJSON" function on the object if there is one - and in this case there is (as part of Spine).

So it looks like either (a) this is a bug in Spine, or (b) I'm doing something incorrectly, which is the more likely option.

I know I can work around this problem by re-configuring the superclass properties on the subclass as well:

SubClass.configure("SubClass", "SuperClassProperty", "SubClassProperty");

However this seems counter-intuitive to me (what's the point of subclassing?), so I'm hoping that's not the answer.

Update: I've done some debugging through the Spine source code, and from what I can tell the problem is the way that I'm configuring the subclass:

    var SubClass = SuperClass.sub();
    SubClass.configure("SubClass", "SubClassProperty");

Calling "configure" here appears to wipe out the attributes from SuperClass. The "toJSON" implementation on the Model prototype is as follows:

Model.prototype.toJSON = function() {
    return this.attributes();
};

Since the attributes collection is reset when SubClass is configured, the SuperClass properties don't come through in the JSON string.

I'm not sure if I shouldn't be calling "configure" on subclassed objects, but I can't find anywhere in the documentation that says I should be doing something else - this is the only reference I can find for subclassing Models (from: http://spinejs.com/docs/models):

Models can be also be easily subclassed:

var User = Contact.sub();
User.configure("User");
Était-ce utile?

La solution

As I suspected, the problem was in the way that I'm using Spine. This comment from the author of Spine infers that using "configure" on a subclass will wipe out the attributes of the superclass. I have to admit I don't understand why this is; it seems counter-intuitive to me, but at least I now know that it's not a bug.

In case anyone else runs into this issue, the way I've worked around it is by adding my own extension method to the Spine Model as follows:

(function () {
    var Model = Spine.Model;

    Model.configureSub = function () {
        var baseAttributes = this.attributes.slice();
        this.configure.apply(this, arguments);

        this.attributes = baseAttributes.concat(this.attributes);
        return this;
    };
})();

Now to configure my subclass:

var SubClass = SuperClass.sub();
SubClass.configureSub("SubClass", "SubClassProperty");

And now my JSON correctly reflects the properties from both the super and subclasses.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top