I need to implement small ODM like feature. I get plain javascript object from database, and I need to convert it into my model class instance. Let's assume model looks like:
class Model{
constructor(){
this.a = '777';
---- whole bunch of other things ---
}
print(){
console.log(this.a);
}
}
So I need convert var a = {b:999, c:666}
to instance of model and being able to call a.print()
after, and when a.print()
executed 777
should be placed in console. How to do that?
There have a simple method. Just assign the object to instance(this)
class Model
{
constructor(obj){
Object.assign(this, obj)
}
print(){
console.log(this.a);
}
}
let obj = {a: 'a', b: 'b', c: 'c'}
let m = new Model(obj)
console.log(m)
m.print() // 'a'
If I understand the question correctly, you can export a factory function and make use of Object.assign
to extend your base Model
:
// Export the factory function for creating Model instances
export default const createModel = function createModel(a) {
const model = new Model();
return Object.assign(model, a);
};
// Define your base class
class Model {
constructor() {
this.a = 777;
}
print() {
console.log(this.a, this.b, this.c)
}
}
And call it like:
const myModel = createModel({ b: 999, c: 666 });
myModel.print();
Babel REPL Example
Or, of course, you could forego the factory and pass a
in as a parameter (or rest parameters) to the constructor but it depends on your preferred coding style.
Just like G_hi3's answer, but it "automates" the creation of the properties object
function Model() {
this.a = '777';
}
Model.prototype.print = function(){
console.log(this.a);
}
// Customize this if you don't want the default settings on the properties object.
function makePropertiesObj(obj) {
return Object.keys(obj).reduce(function(propertiesObj, currentKey){
propertiesObj[currentKey] = {value: obj[currentKey]};
return propertiesObj;
}, {}); // The object passed in is the propertiesObj in the callback
}
var data = {a: '888'};
var modelInstance = Object.create(Model.prototype, makePropertiesObj(data));
// If you have some non trivial initialization, you would need to call the constructor.
Model.call(modelInstance);
modelInstance.print(); // 888
I would suggest rewriting your class to store all its properties in a single JS object this.props
and accept this object in its constructor:
class Model {
constructor (props = this.initProps()) {
this.props = props
// other stuff
}
initProps () {
return {a: '777'}
}
print () {
console.log(this.props.a)
}
}
Then you'll be able to store this.props
in your database as a plain JS object and then use it to easily recreate corresponding class instance:
new Model(propsFromDatabase)
Though, if you don't want to move all properties to this.props
, you could use Object.assign
to keep your object plain:
class Model {
constructor (props = this.initProps()) {
Object.assign(this, props)
// other stuff
}
initProps () {
return {a: '777'}
}
print () {
console.log(this.props.a)
}
}
But I would recommend using the former approach, because it'll keep you safe from name collisions.
How about this?:
var a = Object.create(Model.prototype, {
b: {
enumerable: true, // makes it visible for Object.keys()
writable: true, // makes the property writable
value: 999
}, c: {
value: 666
}
});
You'd be basically creating a new instance of Model from it's prototype and assigning your new properties to it. You should be able to call print
as well.