将 javascript 普通对象转换为模型类实例

问题描述 投票:0回答:8

我需要实现小型 ODM 之类的功能。我从数据库获取纯 JavaScript 对象,我需要将其转换为我的模型类实例。让我们假设模型看起来像:

    class Model{
       constructor(){
           this.a = '777';
           ---- whole bunch of other things ---
       }
       print(){
           console.log(this.a);
       }
   }

所以我需要将

var a = {b:999, c:666}
转换为模型实例,并能够在之后调用
a.print()
,并且当
a.print()
执行时
777
应放置在控制台中。如何做到这一点?

javascript ecmascript-6 odm
8个回答
47
投票

有一个简单的方法。只需将对象分配给实例(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'


8
投票

如果我正确理解了问题,您可以导出工厂函数并利用

Object.assign
来扩展您的基础
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)
  }
}

并称其为:

const myModel = createModel({ b: 999, c: 666 });
myModel.print();

Babel REPL 示例

或者,当然,您可以放弃工厂并将

a
作为参数(或其余参数)传递给构造函数,但这取决于您喜欢的编码风格。


4
投票

如果您需要更一致的类型转换,您还可以创建自己的

typecast
函数,如通用函数

function typecast(Class, obj) {
  let t = new Class()
  return Object.assign(t,obj)
}

// arbitrary class
class Person {
 constructor(name,age) {
   this.name = name
   this.age = age
 }
 print() {
   console.log(this.name,this.age)
 }
}

调用它将任何对象类型转换为任何类实例,例如

let person = typecast(Person,{name:'Something',age:20})
person.print() // Something 20

3
投票

我建议重写你的类,将其所有属性存储在单个 JS 对象中

this.props
并在其构造函数中接受该对象:

class Model {
  constructor (props = this.initProps()) {
    this.props = props
    // other stuff
  }
  initProps () {
    return {a: '777'}
  }
  print () {
    console.log(this.props.a)
  }
}

然后您将能够将

this.props
作为普通 JS 对象存储在数据库中,然后使用它轻松地重新创建相应的类实例:

new Model(propsFromDatabase)

但是,如果您不想将所有属性移动到

this.props
,您可以使用
Object.assign
来保持对象简单:

class Model {
  constructor (props = this.initProps()) {
    Object.assign(this, props)
    // other stuff
  }
  initProps () {
    return {a: '777'}
  }
  print () {
    console.log(this.a)
  }
}

但我建议使用前一种方法,因为它可以让您免受名称冲突的影响。


2
投票

编辑 2024:我认为我最初的想法仍然适合这个特定的用例,但总的来说,以下(用 TypeScript 编写)可能会更好:

class Model {
  a = 11;
  b = 22;
  c = 33;
  constructor(values: Record<"a" | "b" | "c", number> = {}) {
    for (key in values) {
      // to omit extra keys
      if (!(key in this)) continue;
      // to prevent injecting code
      if (typeof this[key] === "function") continue;
      this[key] = values[key];
    }
  }
  print() {
    console.log(this.a)
  }
}

不幸的是,我还没有对此进行测试,因此

for..in
循环中可能存在类型错误,但我认为不存在。无论如何,我原来的解决方案在 TypeScript 中都不起作用:)

原答案:


您可以有一个静态

Model.from
Model.parse
方法,它返回具有这些属性的新模型:

class Model {
  static defaults = { a: 777, b: 888, c: 999, d: 111, e: 222 };
  constructor() {
    const { defaults } = Model;
    for (const key in defaults) this[key] = defaults[key];
  }
  print() {
    console.log(this.a);
  }
  static from(data) {
    return Object.assign(
      new Model(),
      Model.defaults,
      Object.fromEntries(
        Object.entries(data).filter(([key]) => key in Model.defaults)
      )
    );
  }
}

const data = {
  a: "a", b: "b", c: "c", ajkls: "this wont be included"
};
const myModel = Model.from(data);
console.log("myModel =", myModel);
console.log("myModel instanceof Model:", myModel instanceof Model);
console.log("myModel.print():")
myModel.print();


1
投票

这个怎么样?:

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
    }
});

您基本上是从原型创建一个新的模型实例,并将新属性分配给它。您也应该可以拨打

print


0
投票

就像G_hi3的答案一样,但它“自动”创建属性对象

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


0
投票

首先声明一个要转换 JSON 的

class

class LoginResponse {
  constructor(obj) {
    Object.assign(this, obj);
  }
  access_token;
  token_type;
  expires_in;
}

现在将通用 javascript 对象转换为您想要的类对象:

const obj = {
  access_token: 'This is access token1',
  token_type: 'Bearer1',
  expires_in: 123,
};
  let desiredObject = new LoginResponse(obj);
  console.log(desiredObject);

输出将是:

 LOG  {"access_token": "This is access token1", "expires_in": 123, "token_type": "Bearer1"}
© www.soinside.com 2019 - 2024. All rights reserved.