Javascript:如何向属于类的类对象添加属性?
我一直在考虑是否可以做到这一点。如果是,如何进行?我对javaScript世界还相当陌生,所以请容忍我 为了更好地解释我想要实现的目标,我将提供一个小例子: 如您所见,Document类只有一个名为basicDetails的属性。但是它的构造函数接受的Javascript:如何向属于类的类对象添加属性?,javascript,node.js,typescript,ecmascript-6,Javascript,Node.js,Typescript,Ecmascript 6,我一直在考虑是否可以做到这一点。如果是,如何进行?我对javaScript世界还相当陌生,所以请容忍我 为了更好地解释我想要实现的目标,我将提供一个小例子: 如您所见,Document类只有一个名为basicDetails的属性。但是它的构造函数接受的objDocument不仅有基本的细节对象,还有其他属性 let obj = {basicDetails: {type: "draft"}, lineDetails:{lineid:123,itemName:"ite
objDocument
不仅有基本的细节对象,还有其他属性
let obj = {basicDetails: {type: "draft"}, lineDetails:{lineid:123,itemName:"itemName"} }
let doc = new Document(obj)
console.log(doc)
上述代码的输出自然为:
{
"basicDetails": {
"type": "",
"createdDate": "2020-12-03T08:02:59.780Z"
}
}
{
"basicDetails": {
"type": "",
"createdDate": "2020-12-03T08:02:59.780Z"
},
"lineDetails":{"lineid":123,"itemName":"itemName"} }
}
但我希望输出为:
{
"basicDetails": {
"type": "",
"createdDate": "2020-12-03T08:02:59.780Z"
}
}
{
"basicDetails": {
"type": "",
"createdDate": "2020-12-03T08:02:59.780Z"
},
"lineDetails":{"lineid":123,"itemName":"itemName"} }
}
属于objDocument的任何属性:除了基本细节之外的任何
都必须按原样自动添加。并且属性不应该被添加到类的外面
let doc = new Document(obj)
doc["lineDetails] = obj.lineDetials // not acceptable
您可以从传递给文档构造函数的对象中提取基本细节,并使用带扩展语法的解构来识别其余的内容 在这个演示中,我注释掉了typescript部分,因此它可以在这里运行:
类文档{
基本细节/*:基本细节*;
构造函数(objDocument/*:any*/){
设{basicDetails,…rest}=objDocument;
this.basicDetails=新的basicDetails(basicDetails);
对象。分配(此,其余);
}
}
类基本细节{
type/*:字符串*/;
createdDate/*:日期*;
构造函数(objDocument/*:any*/){
this.type=objDocument.type;
this.createdDate=新日期();
}
}
设obj={basicDetails:{type:“draft”},lineDetails:{lineid:123,itemName:“itemName”};
let doc=新文档(obj);
控制台日志(doc)代码>首先,您可以通过提取文档的构造函数选项来简化您的生活。由于您需要根级别的basicDetails
,然后可能需要其他任何内容,因此:
接口文档选项{
基本细节:任何,
[键:字符串]:未知
}
这意味着您至少可以获得某种类型安全性,并防止在没有基本细节的情况下实例化文档
现在,您可以将构造函数更改为提取basicDetails
,以实例化basicDetails
对象,然后将所有其他内容分配给当前实例。为文档
提供[索引签名]意味着它可以具有任意数量的任何属性。将这些属性设置为只读意味着不允许更改它们:
类文档{
基本细节:基本细节;
只读[键:字符串]:未知
构造函数({basicDetails,…otherDetails}:DocumentOptions){
this.basicDetails=新的basicDetails(basicDetails);
分配(此、其他详细信息);
}
}
通过为BasicDetails
的构造函数指定正确的类型,然后使用[ConstructorParameters
]实用程序类型来确保将正确的内容传递给文档,可以进一步提高类型安全性:
接口文档选项{
基本细节:构造函数参数[0],
[键:字符串]:未知
}
类文档{
基本细节:基本细节;
只读[键:字符串]:未知
构造函数({basicDetails,…otherDetails}:DocumentOptions){
this.basicDetails=新的basicDetails(basicDetails);
分配(此、其他详细信息);
}
}
类基本细节{
类型:字符串;
createdDate:日期;
构造函数(对象文档:{}){
this.type=“”;
this.createdDate=新日期();
}
}
设obj={basicDetails:{type:“draft”},lineDetails:{lineid:123,itemName:“itemName”}
let doc=新文档(obj)
doc[“lineDetails”]=obj.lineDetials//不可接受
控制台日志(doc)
如果您想更能经得起未来的考验,那么您可以接受基本细节
的整个参数列表,因此如果构造函数将来发生更改,您不需要更改文档
或文档选项
:
interface DocumentOptions {
basicDetails: ConstructorParameters<typeof BasicDetails>, //no index
[key: string]: unknown
}
class Document {
basicDetails: BasicDetails;
readonly [key: string]: unknown
constructor({ basicDetails, ...otherDetails } : DocumentOptions) {
this.basicDetails = new BasicDetails(...basicDetails);
//pass everything ^^^
Object.assign(this, otherDetails);
}
}
为了方便起见,我添加了一个serialise
方法-它将按照您的期望输出信息:
{
“基本细节”:{
“类型”:“,
“createdDate”:“2020-12-03T09:09:30.355Z”
},
“线路详细信息”:{
“lineid”:123,
“项目名称”:“项目名称”
}
}
它还提供免费克隆功能,因为它输出的数据与构造函数使用的数据完全相同,所以您可以执行以下操作:
let obj={basicDetails:{type:“draft”},lineDetails:{lineid:123,itemName:“itemName”}
let doc1=新文档(obj)
//自由克隆
让doc2=新文档(doc1.serialise());
这是对@trincot answer的改进。首先,设计不是最好的,应该将已经创建的类注入到文档构造函数中
class Document {
basicDetails /*: BasicDetails */;
constructor(basicDetails /*:BasicDetails*/, rest : /*:any*/) {
this.basicDetails = basicDetails
Object.assign(this, rest);
}
}
这是可靠的原则之一(依赖注入)
我反对这种做法。这是可能的,但会使文档
对象难以使用,因为属性现在取决于它是如何实例化的。例如,您可以添加第二个属性otherDetails
,该属性的类型为readonly Record
,任何不属于basicDetails
的内容都会出现在该属性中。这使得文档
对象API更加稳定。@VLAZ实际上,文档的本质是动态的。将要发送给我们的数据看起来像:{basicDetails:{},…插入任何东西..}
所以除了基本细节之外,我们不知道也不关心发送的是什么。这是固定的。其他一切。。我们只是将它存储在DB中,而不关心它的有效性。@VLAZ我知道您建议将任何变量都保存在fixed propertyotherDetails
中,但我们无法控制它。“我们所知道的是,我们将在根部得到一个固定结构的基本细节。”弗拉兹在我考虑poss时说道
let obj = { basicDetails: { type: "draft" }, lineDetails:{ lined : 123, itemName : "itemName" } };
class BasicDetails {
type /*: string */;
createdDate /*: Date */;
constructor(basicDetails /*:basicDetails */) {
this.type = basicDetails.type;
this.createdDate = new Date();
}
}
const { basicDetails, ...rest } = obj
const doc = new Document( new BasicDetails(basicDetails), rest )