从json转换为类型的Typsescript对象 [英] Typsescript object from json casting to type

查看:89
本文介绍了从json转换为类型的Typsescript对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在日常生活中,我需要从ajax中读取一些json并将其转换为某些Typed对象(包括其METHODS)。在互联网上,我发现并使用以下代码进行类型转换:

  export class Obj 
{
public static cast< T>(obj,type:{new(... args):T}):T
{
obj .__ proto__ = type.prototype;
返回对象;
}
}

例如,可以通过以下方式使用: / p>

  let objFromJson = {id:666,名称: love}; 
let building:Building = null;
building = Obj.cast(objFromJson,Building);

//在这一点上,不调用Building的构造函数-这是
//正确,因为我们不创建对象,而只进行类型转换

building.test ('xx');

//在控制台上的这一点上,我们应该得到:
//> building.test a:xx,name:love

//因此对象 building确实具有Building Class


其中(示例来自 head)

 出口类建筑物{ b 
$ b构造函数(
公共ID:数字,
公共名称:字符串,
){
console.log('building.constructor:id:'+ id +',name'+名称);
}

公开测试(a){
console.log(’building.test a:’+ a +’,名称:’+ this.name);
}

}

其他信息:代替使用 cast< T>(obj,类型:{new(... args):T}):T 我们只能使用 cast< T>( obj,类型):T ,但我读到第二个版本会导致箭头功能出现问题( https:// stackoverflow.com/a/32186367/860099 )-我不明白为什么-?



问题:我不是真的了解Obj.cast方法的工作原理(例如,如何使用 ... args 进行调用)-有人可以解释吗?是否有人以类似方便的方式知道替代函数,但不是用于铸造而是用于CREATE对象(因此称为构造函数)以json数据形式生成json数据(例如 building = Obj.create(objFromJson,Building);

解决方案

cast 的工作方式



Javascript使用原型继承 __ proto __ 属性代表当前对象的原型,这决定了给定对象的类型


对于使用对象文字创建的对象,此值为Object.prototype;对于使用数组文字创建的对象,此值为Array.prototype;对于函数,此值为Function.prototype。佛r使用new fun创建的对象,其中fun是JavaScript提供的内置构造函数之一(数组,布尔值,日期,数字,对象,字符串等-包括随着JavaScript的发展而添加的新构造函数),此值是总是很有趣。 对于使用新乐趣创建的对象,其中 fun 是脚本中定义的函数,该值为fun.prototype的值。


因此,当您更改 __ proto __ 更改对象的原型链,从而基本上更改其类型。



类型:{new(... args):T} 表示构造函数的方式在打字稿中。就像上面的引文所说,对于由函数(例如 type )构造的对象, __ ptoto __ 应该是<$函数的c $ c>原型。



因此,在设置 __ proto __ 时, cast 基本上模拟了使用 type 构造函数作为参数传递来构造对象的事实。



这种方法的问题



问题在于构造函数实际上并没有被调用,您只是在模拟使用给定构造函数创建对象的事实。因此,构造函数中发生的任何初始化都不会执行。例如,箭头函数需要捕获 this ,因此它们不是在构造函数的 prototype 上设置,而是在构造函数调用期间对象的实例,因此,如果不调用构造函数,则不会初始化箭头函数:

 导出类Building {
private otherField:string;
构造函数(
公用ID:数字,
公用名称:字符串,
){
console.log('building.constructor:id:'+ id +' ,名称'+名称);
this.otherField = name + id;
// Ts在JS中添加了用于初始化箭头函数的代码,但是想法是一样的,这就是它发生的地方
}

public arrow =()= > {};
公开测试(a){
console.log(’building.test a:’+ a +’,名称:’+ this.name);

//如果使用强制转换,则下面的两个字段均未定义。
console.log(‘building.otherField’+ this.otherField +’,箭头:’+ this.arrow); }
}

替代 cast



另一种方法是创建该类的新实例并使用 Object.assign 来分配 json 对象的属性。乍一看,这似乎较慢,但是文档说更改 __ ptoto __ 非常慢,不建议


根据现代JavaScript引擎如何优化属性访问的性质,更改对象的[[Prototype]]在每个浏览器和JavaScript引擎中都是非常缓慢的操作。




 出口等级大楼{
public id:number;
公共名称:字符串;
构造函数(data:Partial< Building>){
Object.assign(this,data)
console.log('building.constructor:id:'+ this.id +',名称'+ this.name);
}

公开测试(a){
console.log(’building.test a:’+ a +’,名称:’+ this.name);
}

}
let objFromJson = {id:666,name: love};
let building:建筑物=新建筑物(objFromJson);

如果该类没有任何方法,也许您可​​以更改设计以使其没有,那么我只需要使用一个接口来输入JSON对象并继续使用原始JSON对象即可。


In daily life I need to read some json from ajax and cast it to some Typed object (including its METHODS). On internet I found and use following code to type casting:

export class Obj 
{
    public static cast<T>(obj, type: { new(...args): T} ): T 
    {
        obj.__proto__ = type.prototype;
        return obj;
    }
}

As example It can be use in following way:

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

where (example is from '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);
    }

}

Additional info: Instead of using cast<T>(obj, type: { new(...args): T} ): T we can use just cast<T>(obj, type): T but I read that second version will cause problem with arrow functions (https://stackoverflow.com/a/32186367/860099) - I don't understand why - ?

Questions: I not really understand how method Obj.cast works (and for instance how I can use ...args on calling it) - can someone explain it? Do someone know alternative function but not for casting but for CREATE object (so call constructor) form json data in similar handy way (eg. building = Obj.create(objFromJson, Building);

解决方案

How cast works

Javascript uses prototypical inheritance. The __proto__ property, represents the prototype of the current object. This is what determines the type of the given object

For objects created using an object literal, this value is Object.prototype. For objects created using array literals, this value is Array.prototype. For functions, this value is Function.prototype. For objects created using new fun, where fun is one of the built-in constructor functions provided by JavaScript (Array, Boolean, Date, Number, Object, String, and so on — including new constructors added as JavaScript evolves), this value is always fun.prototype. For objects created using new fun, where fun is a function defined in a script, this value is the value of fun.prototype.

So when you change the __proto__ you change the prototype chain for the object basically changing it's type.

type: { new(...args): T} it the way you can represent a constructor function in typescript. As the above quote says for an object constructed by a function (such as type) the __ptoto__ should be the prototype of the function.

So when setting the __proto__, cast basically simulates the fact that the object was constructed using the type constructor function passed as a parameter.

Problems with this approach

The problems is that the constructor doesn't actually get invoked, you are just simulating the fact that the object was created using the given constructor. So any initialization that occurs in the constructor does not get executed. Arrow functions for example need to capture this, so they are not set on the prototype of the constructor function but rather on the instance of the object during the invocation of the constructor so if the constructor does not invoked, arrow functions are not initialized:

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

Alternative to cast

An alternative would be to create a new instance of the class and use Object.assign to assign the properties from the json object. At first glance this may seem slower, but the documentation says changing the __ptoto__ is very slow and not recommended

Changing the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation, in every browser and JavaScript engine.

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

If the class does not have any methods, and maybe you can change your design so it does not, then I would just use an interface to type the JSON object and keep using the original JSON object.

这篇关于从json转换为类型的Typsescript对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆