指南:非普通对象类型(类)
作为一个基本的工作定义,非普通对象类型——即,类——是可实例化的对象,其自身原型不是 Object——例如,Array 是一个原生非普通对象类型。
许多常用的原生非普通对象类型已经完全兼容并支持在故事变量中使用——例如,Array、Date、Map 和 Set。另一方面,所有其他非普通对象类型必须被改造为兼容,才能成功存储在故事变量中。
使自定义非普通对象类型完全兼容需要在它们的原型上添加两个方法,.clone() 和 .toJSON(),以支持实例的克隆——即,深拷贝。
.clone()方法需要返回实例的一个克隆。.toJSON()方法需要返回一个代码字符串,该字符串在被求值时会返回实例的一个克隆。
示例:class 语法(较新,推荐)
配置对象参数构造函数(自动复制自身数据):
javascript
window.Character = class Character {
constructor(config) {
// 用一些默认值设置我们自己的数据属性。
this.name = '(none)';
this.race = '(none)';
this.st = 10;
this.dx = 10;
this.iq = 10;
this.ht = 10;
this.hp = 10;
// 将给定配置对象的自身属性克隆到我们自己的属性中。
//
// 注意:我们使用 SugarCube 内置的 `clone()` 函数来深拷贝
// 每个属性的值。
Object.keys(config).forEach((pn) => {
this[pn] = clone(config[pn]);
});
}
clone() {
// 返回一个包含我们自身数据的新实例。
return new this.constructor(this);
}
toJSON() {
// 返回一个代码字符串,该字符串将创建一个包含我们自身数据的新实例。
//
// 注意:将 `this` 直接作为 `reviveData` 参数提供给
// `Serial.createReviver()` 调用会触发序列化器中失控的递归,
// 因此我们必须改为传入我们自身数据的克隆。
const ownData = {};
Object.keys(this).forEach((pn) => {
ownData[pn] = clone(this[pn]);
});
return Serial.createReviver(`new ${this.constructor.name}($ReviveData$)`, ownData);
}
};创建一个新实例:
plain
<<set $Joe to new Character({
name : 'Joe the Barbarian',
race : 'human',
st : 20,
dx : 12,
iq : 9,
ht : 18,
hp : 18
})>>离散参数构造函数(手动复制自身数据):
javascript
window.Character = class Character {
constructor(name, race, st, dx, iq, ht, hp) {
this.name = name ?? '(none)';
this.race = race ?? '(none)';
this.st = st ?? 10;
this.dx = dx ?? 10;
this.iq = iq ?? 10;
this.ht = ht ?? 10;
this.hp = hp ?? 10;
}
clone() {
return new this.constructor(
this.name, this.race, this.st, this.dx, this.iq, this.ht, this.hp
);
}
toJSON() {
return Serial.createReviver(String.format(
'new {0}({1},{2},{3},{4},{5},{6},{7})',
this.constructor.name,
JSON.stringify(this.name), JSON.stringify(this.race),
JSON.stringify(this.st), JSON.stringify(this.dx), JSON.stringify(this.iq),
JSON.stringify(this.ht), JSON.stringify(this.hp)
));
}
};function 语法(经典,不推荐)
function 语法示例与 class 语法示例等价,只是使用经典的构造函数 + 原型方法形式。由于篇幅关系,此处从略,请参阅官方文档。