Typescript遇到的一个奇妙问题
2018-12-21 23:18
前两天在编写TypeScript(v3.2.2)逻辑时,遇到了一个奇妙的问题阻碍了我一点时间,我用下面的代码来复现并解释一下这个问题。
问题重现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| // test.ts class GameObject { protected id = 0; constructor(data) { this.update(data); } update(data) { this.id = data.id; } }
class Role extends GameObject { name = ""; update(data) { super.update(data); this.name = data.name; } }
let role = new Role({ id: 1, name: "fox" }); console.log(role.name);
|
试着猜想一下上面这份代码编译执行之后会打印什么,当然我希望的是打印出fox。但在实际运行之后打印的结果有些出乎我的意料,它打印了’’(空字符串),这不是我想要的结果。我很疑惑,但是从这份代码上似乎看不出有什么问题,就只好从编译之后的JavaScript代码下手,试着找出造成这个问题的答案。
下面是编译之后的JavaScript代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| // test.js var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); } return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var GameObject = /** @class */ (function () { function GameObject(data) { this.id = 0; this.update(data); } GameObject.prototype.update = function (data) { this.id = data.id; }; return GameObject; }()); var Role = /** @class */ (function (_super) { __extends(Role, _super); function Role() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.name = ""; return _this; } Role.prototype.update = function (data) { _super.prototype.update.call(this, data); this.name = data.name; }; return Role; }(GameObject)); var role = new Role({ id: 1, name: "fox" }); console.log(role.name);
|
于是,我们从Role类的构建方法就能得出问题的答案。在Role的构建方法中首先调用GameObject的构造方法(_super)进行初始化,由于我们的Role类重写了GameObject的update方法,所以我们如愿以偿的初始化了name与id两个成员变量,但是基类构建方法执行完毕之后才开始进行Role的成员初始化,所以导致Role的成员变量初始值覆盖了之前我们在update中改变的变量值而造成了这个问题。
1 2 3 4 5
| function Role() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.name = ""; return _this; }
|
补充
如果觉得之前那份代码用来举例不是很好的话,也可以看一下这份,它们拥有一样的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| abstract class GameObject { constructor(data) { this.update(data); } abstract update(data); }
class Role extends GameObject { name = ""; update(data) { this.name = data.name; } }
let role = new Role({ name: "fox" }); console.log(role.name);
|
临时解决方式
我们就找到了造成问题的地方,接下来我们试着解决它。
方式1
添加Role类的constructor方法,并在下面做一个判定来检查是否为空后赋初始值。
1 2 3 4 5 6
| // test.ts constructor(data) { super(data) if (!this.name) this.name = ""; }
|
方式2
添加Role类的constructor方法,但是这样就调用了两次update方法,感觉也并不是很好。
1 2 3 4 5
| // test.ts constructor(data) { super(data); this.update(data); }
|
当然解决的办法并不只是这两种,还有很多就不一一例举了.
后记
我认为这是TyperScript的一个bug,所以我已经在github提了issue,或许在过一段时间之后微软就会修复这个问题了吧~