繁体   English   中英

为什么 instanceof 在 babel-node 下的 Error 子类的实例上不起作用?

[英]Why doesn't instanceof work on instances of Error subclasses under babel-node?

我看到在 OS X 上的babel-node版本 6.1.18/Node 版本 5.1.0 下运行时, instanceof运算符不适用于Error子类的实例。这是为什么? 相同的代码在浏览器中运行良好,以我的小提琴为例。

以下代码在浏览器中输出为true ,而在 babel-node 下为假:

class Sub extends Error {
}

let s = new Sub()
console.log(`The variable 's' is an instance of Sub: ${s instanceof Sub}`)

我只能想象这是由于 babel-node 中的一个错误,因为instanceof适用于除Error之外的其他基类。

.babelrc

{
  "presets": ["es2015"]
}

编译输出

这是 babel 6.1.18 编译的 JavaScript:

'use strict';

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var Sub = (function (_Error) {
  _inherits(Sub, _Error);

  function Sub() {
    _classCallCheck(this, Sub);

    return _possibleConstructorReturn(this, Object.getPrototypeOf(Sub).apply(this, arguments));
  }

  return Sub;
})(Error);

var s = new Sub();
console.log('The variable \'s\' is an instance of Sub: ' + (s instanceof Sub));

tl;dr 如果您使用的是 Babel 6,则可以使用https://www.npmjs.com/package/babel-plugin-transform-b​​uiltin-extend

Babel 从未支持扩展内置类型,如ArrayError等。 它在真实的 ES6 环境中完全有效,但有一些要求使其工作很难以与旧浏览器兼容的方式进行转换。 它在 Babel 5 中“有效”,因为它没有抛出错误,但是从扩展子类实例化的对象并没有像他们应该的那样工作,例如:

class MyError extends Error {}

var e1 = new MyError();
var e2 = new Error();

console.log('e1', 'stack' in e1);
console.log('e2', 'stack' in e2);

结果是

e1 false
e2 true

虽然它没有出错,但子类没有像错误应该那样正确地获得“堆栈”。 类似地,如果您要扩展Array它的行为可能有点像数组,并且具有数组方法,但它的行为并不完全像数组。

Babel 5 文档特别指出这是需要注意的类的边缘情况。

在 Babel 6 中,类在子类化的处理方式上被更改为更符合规范,其副作用是现在上面的代码仍然无法工作,但它不会以与以前不同的方式工作。 这已在https://phabricator.babeljs.io/T3083 中介绍,但我将在此处详细说明一个潜在的解决方案。

要返回 Babel 5 的子类化行为(记住,仍然不正确或不推荐),您可以将内置构造函数包装在您自己的临时类中,例如

function ExtendableBuiltin(cls){
    function ExtendableBuiltin(){
        cls.apply(this, arguments);
    }
    ExtendableBuiltin.prototype = Object.create(cls.prototype);
    Object.setPrototypeOf(ExtendableBuiltin, cls);

    return ExtendableBuiltin;
}

有了这个帮手,而不是做

class MyError extends Error {}

class MyError extends ExtendableBuiltin(Error) {}

但是,在您的特定情况下,您已经说过您使用的是 Node 5.x。 Node 5 支持原生 ES6 类,无需转译。 我建议您通过删除es2015预设来使用node5 ,而是使用node5以便您获得本机类等。 在这种情况下,

class MyError extends Error {}

将按照您期望的方式工作。

对于不使用 Node 4/5 或仅使用最新 Chrome 的人,您可能需要考虑使用类似https://www.npmjs.com/package/error 的内容 您还可以探索https://www.npmjs.com/package/babel-plugin-transform-b​​uiltin-extend 其中的approximate选项与 Babel 5 的行为相同。请注意,非approximate行为绝对是边缘情况,可能无法在 100% 的情况下工作。

如果编译目标设置为“es5”, instanceof将不适用于子类错误。 我设定的目标为“ES6”在我tsconfig.jsoninstanceof产生正确的结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM