在日常生活中,我需要从ajax中读取一些json并将其转换为某些Typed对象(包括其METHODS)。在互联网上,我发现并使用以下代码来输入:
export class Obj
{
public static cast<T>(obj, type: { new(...args): T} ): T
{
obj.__proto__ = type.prototype;
return obj;
}
}
例如可以按以下方式使用:
let objFromJson = { id: 666, name: "love" };
let building: Building = null;
building = Obj.cast(objFromJson, Building);
// On this point constructor for Building is not call - this is
// correct because we not create object but only make type casting
building.test('xx');
// on this point on console we should get:
// > "building.test a:xx, name:love"
// so object 'building' indeed have methods of Building Class
其中(例如来自'head')
export class Building {
constructor(
public id: number,
public name: string,
) {
console.log('building.constructor: id:' + id + ', name' + name);
}
public test(a) {
console.log('building.test a:' + a + ', name:' + this.name);
}
}
其他信息:我们只使用cast<T>(obj, type: { new(...args): T} ): T
而不是cast<T>(obj, type): T
,但我读到第二个版本会导致箭头功能出现问题(https://stackoverflow.com/a/32186367/860099) - 我不明白为什么 - ?
问题:我真的不明白Obj.cast方法是如何工作的(例如我如何使用...args
来调用它) - 有人可以解释一下吗?有人知道替代函数但不是为了铸造而是为了CREATE对象(所以调用构造函数)以类似的方式形成json数据(例如。building = Obj.create(objFromJson, Building);
答案 0 :(得分:1)
cast
如何运作
Javascript使用prototypical inheritance。 __proto__
属性表示当前对象的原型。这是决定给定对象类型的原因
对于使用对象文字创建的对象,此值为Object.prototype。对于使用数组文字创建的对象,此值为Array.prototype。对于函数,此值为Function.prototype。对于使用new fun创建的对象,fun是JavaScript提供的内置构造函数之一(Array,Boolean,Date,Number,Object,String等等 - 包括作为JavaScript演变添加的新构造函数),此值为总是fun.prototype。 对于使用
new fun
创建的对象,其中fun
是脚本中定义的函数,此值为fun.prototype的值。
因此,当你更改__proto__
时,你改变了对象的原型链,基本上改变了它的类型。
type: { new(...args): T}
它可以表示typescript中的构造函数。正如上面的引用所说的由函数构造的对象(例如type
),__ptoto__
应该是函数的prototype
。
因此,在设置__proto__
时,cast
基本上模拟了使用作为参数传递的type
构造函数构造对象的事实。
此方法存在问题
问题是构造函数实际上没有被调用,你只是在模拟使用给定构造函数创建对象的事实。因此,构造函数中发生的任何初始化都不会被执行。例如,箭头函数需要捕获this
,因此它们不会在构造函数的prototype
上设置,而是在调用constructor
期间设置在对象的实例上,因此如果没有调用构造函数,箭头函数没有初始化:
export class Building {
private otherField : string;
constructor(
public id: number,
public name: string,
) {
console.log('building.constructor: id:' + id + ', name' + name);
this.otherField = name+id;
// Ts adds in the code for initializing arrow functions in JS, but the idea is the same, this is where it would happen
}
public arrow = ()=> {};
public test(a) {
console.log('building.test a:' + a + ', name:' + this.name);
// both fields below will be undefined if cast was used.
console.log('building.otherField' + this.otherField + ', arrow:' + this.arrow); }
}
替代cast
另一种方法是创建类的新实例,并使用Object.assign
分配json
对象的属性。乍一看这似乎有点慢,但是文档说改变__ptoto__
非常慢而且不推荐
根据现代JavaScript引擎如何在每个浏览器和JavaScript引擎中优化属性访问,非常慢的操作,改变对象的[[Prototype]]。
export class Building {
public id: number;
public name: string;
constructor(data: Partial<Building>){
Object.assign(this, data)
console.log('building.constructor: id:' + this.id + ', name' + this.name);
}
public test(a) {
console.log('building.test a:' + a + ', name:' + this.name);
}
}
let objFromJson = { id: 666, name: "love" };
let building: Building = new Building(objFromJson);
如果该类没有任何方法,并且您可以更改您的设计,那么我只会使用一个接口来键入JSON对象并继续使用原始JSON对象。