我建议我们在使用--target ES5
编译时,为扩展ES6内置类的类示例构造运行时语义添加一个新的辅助函数。
背景
我们当前为--target ES5
生成的类假设其超类遵循与我们生成的类相同的运行时语义。通常这意味着可以通过call()
或apply()
将构造函数作为函数调用。然而,一些ES6内置类在未用作构造函数时被指定为抛出异常(即Promise
、Map
等),而其他ES6内置类在调用时返回值,忽略提供给call()
或apply()
的this
值(即Error
、Array
等)。
以前我们为支持后一种情况提供了可能的解决方法,但目前我们还没有解决方案来解决前一种情况。
建议
以下代码清单描述了我们需要为包含显式(或隐式,用于属性声明)的super()
调用的任何文件发出的新__construct
辅助函数:
class MyPromise extends Promise {
constructor(executor) {
super(executor);
}
}
// becomes...
var __extends = ...;
var __construct = (this && this.__construct) || (typeof Reflect !== "undefined" && Reflect.construct
? function (s, t, a, n) { return t !== null ? Reflect.construct(t, a, n) : s; }
: function (s, t, a) { return t !== null && t.apply(s, a) || s; });
var MyPromise = (function (_super) {
__extends(MyPromise, _super);
function MyPromise(executor) {
var _this = this;
var _newTarget = this.constructor;
_this = __construct(this, _super, [executor], _newTarget);
return _this;
}
return MyPromise;
})(Promise);
好处
- 通过特性检测
Reflect.construct
,允许下级类发射扩展ES6内置类(如果在ES6宿主中运行)。 - 在ES5宿主中运行时回退到现有行为。
- 当
x
等于null
时,以与现有行为相同的方式处理extends null
和extends x
。 - 以与现有行为相同的方式处理来自
super
的自定义返回值。
缺点
- 更大的辅助函数占用空间
- 在ES5宿主中对内置类进行子类化与在ES6宿主中对内置类进行子类化具有不同的运行时语义:
- 在ES5中,对
Array
或Error
进行子类化将不具有正确的原型链。唯一的解决方案是根据已建立的指导方针,使用非标准属性__proto__
显式设置原型链。
3条答案
按热度按时间u0sqgete1#
尽管这将增加更多的辅助开销,但我们可以通过$x_{1m0n1}^{x}$来考虑一种最佳努力的方法来解决子类化缺点:
$x_{1a0b1}^{x}$
qco9c6ql2#
尝试使用原生WebComponents与Typescript目前并不十分符合人体工程学,因为首先我们需要针对
es2015
(或更高目标),然后使用支持此功能的babel
。我知道添加大量特定设置可能需要避免,但是否可以最小化更改,使其具有一个标志(例如
useClassReflectConstruct
),始终输出Reflect.construct(...)
而不是.apply(...)
?在es5浏览器中简单地包含一个polyfill for
Reflect.construct
,并在tsconfig.json
中设置此选项以支持使用Web组件和扩展原生对象而无需麻烦。对于同一功能还有三个其他问题待解决。是什么阻碍了这一进展?它可以作为PR添加吗?
zd287kbt3#
使用
Reflect.construct
编译的问题是,this.constructor
属性不能被覆盖或以其他方式阻碍;但这与支持编译new.target
所需的警告相同。