convert javascript plain object into model class i

2019-04-23 11:13发布

问题:

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?

回答1:

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'



回答2:

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.



回答3:

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



回答4:

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.



回答5:

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.