将javascript普通对象转换为模型类实例
Posted
技术标签:
【中文标题】将javascript普通对象转换为模型类实例【英文标题】:convert javascript plain object into model class instance 【发布时间】:2016-02-20 02:56:11 【问题描述】:我需要实现类似 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
应该放在控制台中。该怎么做?
【问题讨论】:
b:999, c:666
怎么会变成Model
实例?您的 Model
s 只有 a
属性,而不是 b
或 c
属性。也许这就是人们不理解您的问题的原因。
@Bergi 它可能是对象中的几十个字段,我认为它们都不应该在构造函数中列出。
@silent_coder:当然你所有的字段都应该在构造函数中列出来?如果没有创建,实例将不会有这些字段。
@Bergi 这是 javascript 伙伴。你可以用任何方法输入this.b = xxx
,它是完全有效的。
在我看来,这就像 Casting plain objects to function instances (“classes”) in javascript 的副本(在 ES6 中没有什么不同)。请告诉我这是否有帮助。
【参考方案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
);
你基本上是从它的原型创建一个新的 Model 实例并将你的新属性分配给它。你应该也可以拨打print
。
【讨论】:
我需要编写自动化代码来将 pojso 转换为模型实例。我无法手动填写属性。 是的,属性也可以用enumerable
、writable
、configurable
和get
和set
这样修改:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…【参考方案2】:
如果我理解正确,您可以导出一个工厂函数并使用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 Example
或者,当然,您可以放弃工厂并将a
作为参数(或其余参数)传递给构造函数,但这取决于您喜欢的编码风格。
【讨论】:
我会推荐class Model static create(a) … …
,也许还有一个更具描述性的名字,比如createFrom
或fromJSON
如果a.a
最初包含不同的值会怎样。比方说'-500'?我认为一些数据会丢失。或者在普通对象中,或者在构造函数中设置。如果随时间的模型将使用属性扩展并且只读 getter 与普通对象中的字段同名,这种情况将如何工作?
@Ph0en1x 问题中没有指定任何内容。无论哪种方式,将Object.assign
中的 source 对象转换为排除键都是微不足道的。
@Ph0en1x:试试看?最后一个值将覆盖前一个值。稍后(在构造之后)扩展实例是一种反模式。只读 getter 当然会导致问题,您必须调整 createModel
方法以明确使用它们。【参考方案3】:
就像 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
【讨论】:
不过,这仍然缺少对构造函数的调用。 @Bergi 我故意没有调用构造函数,因为它会覆盖this.a = '777';
中传递的数据。
你可以(应该)在传入数据之前调用它,我的意思是。如果您不调用它,您可能缺少实例的初始化。【参考方案4】:
我建议重写你的类,将其所有属性存储在单个 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)
但我建议使用前一种方法,因为它可以保护您免受名称冲突。
【讨论】:
这并不单独默认每个属性,而是仅默认整个props
对象。
@Bergi 是的,这是您对 ODM 的期望——要么从 DB 中读取所有内容,要么从头开始创建。
另外,新的Model(b:999, c:666).print()
// a === undefined
@RGraham 是的,因为它在this.props.a
中。但无论如何,好点。添加了替代方法。
这种方法有严重的缺点。如果您以后需要使用您的属性,例如(new Model(a)).b
,您将需要为任何属性实现自定义 getter。这是大量的工作。【参考方案5】:
有一个简单的方法。只需将对象分配给实例(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'
【讨论】:
【参考方案6】:如果您需要更一致的类型转换,您还可以创建自己的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
【讨论】:
【参考方案7】:你可以有一个静态的 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)
const defaults = Model;
return Object.assign(
new Model(),
Object.keys(data)
.filter((key) => defaults[key])
.reduce((prev, curr) => (
...prev, [curr]: data[curr]
), 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();
【讨论】:
以上是关于将javascript普通对象转换为模型类实例的主要内容,如果未能解决你的问题,请参考以下文章
javascript 面向对象设计之 Function 普通类
django的模型类管理器-----------数据库操作的封装