Years ago, I wrote my own "declare" implementation that mimicked Dojo's (anyone?): https://github.com/mercmobily/simpleDeclare This is now made obsolete by class
. The beauty of SimpleDeclare is that I could do this:
// Basic definition of the managers store
var Managers = declare( JsonRestStores, JsonRestStores.HTTPMixin, JsonRestStores.SimpleDbLayerMixin, {
schema: new Schema({
name : { type: 'string', trim: 60 },
surname: { type: 'string', searchable: true, trim: 60 },
}),
storeName: 'managers',
publicURL: '/managers/:id',
handlePut: true,
handlePost: true,
handleGet: true,
handleGetQuery: true,
handleDelete: true,
});
var managers = new Managers();
Yes, it had multiple inheritance; and yes, things like handePut
, handlePost
, etc. were placed in a "middle-man" prototype.
Having to convert this code to ES6, I Have two options:
(Let's not cover "mixins" for now...)
// Basic definition of the managers store
class Managers extends JsonRestStores {
static get schema() { return new Schema({
name : { type: 'string', trim: 60 },
surname: { type: 'string', searchable: true, trim: 60 },
}),
static get storeName() { return 'managers' }
static get publicURL() { return '/managers/:id' }
static get handlePut() { return true }
static get handlePost() { return true }
static get handleGet() { return true }
static get handleGetQuery() { return true }
static get handleDelete() { return true }
};
var managers = new Managers()
// Basic definition of the managers store
class Managers extends JsonRestStores {
schema = new Schema({
name : { type: 'string', trim: 60 },
surname: { type: 'string', searchable: true, trim: 60 },
})
storeName = 'managers'
publicURL = '/managers/:id'
handlePut = true
handlePost = true
handleGet = true
handleGetQuery = true
handleDelete = true
};
var managers = new Managers()
The problem is that neither of these solutions really work as well as prototypes; having those values in the prototype gave 1) Defaults 2) The ability to an instance to find out what the parent's values were (e.g. manager.constructor.prototype). 3) The ability for an instance to change those values (this can be useful at times)
If I use static get
, I get something that is quite verbose, with the upside that an instance can figure out the values of the parent, and parent's parent, is; and, unless I create setters for each one, I can't modify those values either
If I use class fields (which don't even exist yet), I get better syntax, with the major downside that an instance can't figure out what the earlier defaults were (since all values are in the instance)
What would you do?
Option 1 creates new Schema
instance each time the property is accessed, which is inadmissible overhead, unless this is desirable behaviour.
Option 2 creates new Schema
instance for each Managers
instance. If Managers
is subclassed and schema
is overridden, Schema
will be instantiated any way, which provides overhead.
If all Managers
instances are supposed to share same schema
instance, it should be assigned to class prototype:
Managers.prototype.schema = new Schema(...);
It can also be defined as static property and be optionally doubled with a getter to provide easier access on class instance.
In ES.next:
class Managers extends JsonRestStores {
static schema = new Schema(...);
get schema() {
return this.constructor.schema;
}
...
}
In ES6:
class Managers extends JsonRestStores {
get schema() {
return this.constructor.schema;
}
...
}
Managers.schema = new Schema(...);