我希望在扩展Object的类上定义自定义toString会覆盖基类的toString函数。但是,这似乎不适用..有没有人知道为什么会这样?
代码如下:
class Person extends Object {
constructor(public name:string){
super();
this.name = name;
}
public toString():string {
return 'hi i am ' + this.name;
}
}
var john = new Person("john");
console.log(john.toString());
这段代码输出[object object],我希望它能调用person类的toString ..
当我像下面的代码一样编写它时,它可以工作,但理由是什么?
class Person {
constructor(public name:string){
this.name = name;
}
public toString():string {
return 'hi i am ' + this.name;
}
}
var john = new Person("john");
console.log(john.toString());
进一步测试时,当我创建一个从Object扩展的类时,它的所有方法都不可用......所以如果我要创建一个类如下的类:
class Person extends Object {
constructor(public name:string){
super();
this.name = name;
}
public toStringTest():string {
return 'hi i am ' + this.name;
}
}
var john = new Person("john");
console.log(john.toStringTest()); <-- ERROR HERE AT RUNTIME
在运行时会出错,说明此方法不可用..
这是预期的行为吗?
对于记录:我在NodeJS中的VSCode中使用TypeScript并从TS转换回es5 ...然后我使用NodeJS运行它..
TIA,
约翰。
答案 0 :(得分:2)
嗯,原因在于转换后的代码:
var __extends = (this && this.__extends) || (function () {
var 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 function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var Person = /** @class */ (function (_super) {
__extends(Person, _super);
function Person() {
return _super !== null && _super.apply(this, arguments) || this;
}
Person.prototype.toString = function () {
return 'hi';
};
return Person;
}(Object));
var p = new Person();
正如您在Person
函数(Person
的构造函数)的定义中所看到的那样,它将结果返回给调用_super.apply(this, arguments)
。所以,实质上是返回Object()
,它基本上是一个空对象。而且,此外,它将结果对象的原型设置为Object
的原型,实际上是Object的直接后代并忽略Person
原型。实际上,如果您在控制台中执行代码并执行:
p instanceof Person
你得到false
如果你这样做
p.__proto__ === Object.prototype
你得到true
。
所以永远不要来自Object
。隐含地,所有目标都已经存在。
但是,为什么会发生这种情况?
好吧,正如我们所看到的,构造函数返回_super.apply(this, arguments) || this
。
这意味着,如果调用没有new
的构造函数返回undefined
(通常用于几乎所有类,其构造函数没有return
语句),那么我们得到{{ 1}},并且所有工作都按预期进行。
问题是,根据ECMASCript规范,如果对它的调用(调用this
)返回不是对象的东西,则构造函数返回this
。对于返回空对象的.call()
而言,情况并非如此,而大多数构造函数都没有(如上所述,它们返回Object()
)。所以这里,TypeScript遵循相同的约定,并且,undefined
本身返回Object()
,所有派生类也是如此,只有增强属性。
在示例中,如果您向{ }
添加name
属性,则可以执行以下操作:
Person
即使const p = new Person();
p.name = 'John';
不是p
类型,而是Person
。
TypeScript转换使构造函数始终返回Object
。通常,这与_this
相同(当您使用this
调用时,构造函数隐式返回的内容),因此不会造成任何损害。但是,当然,这意味着,如果您在控制台中执行转换后的代码,则可以执行以下操作:
new
并且它会给你一个漂亮的空对象(就像Person();
一样,从中明确地显示它!这样,行为是合乎逻辑的。)
如果您添加属性,例如Object
,则调用name
将为您提供具有此类属性的对象。
所以,正如更正确的结论:不要从没有Person()
的情况下工作的构造函数派生出来,并且当你以这种方式调用时,你不确定他们做了什么。