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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33870684/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 16:59:23  来源:igfitidea点击:

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

javascriptnode.jsecmascript-6babeljs

提问by aknuds1

I am seeing that the instanceofoperator doesn't work on instances of Errorsubclasses, when running under babel-nodeversion 6.1.18/Node version 5.1.0 on OS X. Why is this? The same code works well in the browser, try my fiddlefor an example.

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

The following code outputs truein the browser, whereas under babel-node it's false:

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

class Sub extends Error {
}

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

I can only imagine this being due to a bug in babel-node, since instanceofworks for other base classes than Error.

我只能想象这是由于 babel-node 中的一个错误,因为它instanceof适用于Error.

.babelrc

.babelrc

{
  "presets": ["es2015"]
}

Compiled Output

编译输出

This is the JavaScript compiled by babel 6.1.18:

这是 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));

回答by loganfsmyth

tl;dr If you're on Babel 6, you can use https://www.npmjs.com/package/babel-plugin-transform-builtin-extend

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

Extending builtin types like Arrayand Errorand such has never been supported in Babel. It is perfectly valid in a real ES6 environment, but there are requirements to make it work that are very difficult to transpile in a way that is compatible with older browsers. It "worked" in Babel 5 in that it didn't throw an error, but objects instantiated from the extended subclass did not work like they were supposed to, for example:

Babel 从未支持扩展诸如Arrayand 之Error类的内置类型。它在真实的 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);

results in

结果是

e1 false
e2 true

While it did not error out, the subclass does not properly get a 'stack' like errors are supposed to. Similarly, if you were to extend Arrayit might behave somewhat like an array, and have array methods, but it did not behave fully like an array.

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

The Babel 5 documentation specifically called this out as an edge-case of classes to be aware of.

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

In Babel 6, classes were changed to be more spec-compliant in how subclassing is handled, and a side-effect of that is that now the above code will stillnot work, but it will not work in a different way than before. This has been covered in https://phabricator.babeljs.io/T3083, but I'll elaborate here on a potential solution.

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

To return Babel 5 subclassing behavior (which remember, is still not right or recommended), you can wrap the builtin constructor in your own temporary class, e.g.

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

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

    return ExtendableBuiltin;
}

With this helper, rather than doing

有了这个帮手,而不是做

class MyError extends Error {}

do

class MyError extends ExtendableBuiltin(Error) {}

In your specific case however, you have said that you are on Node 5.x. Node 5 has support for native ES6 classes without transpiling. I'd recommend you use those by dropping the es2015preset and instead using node5so you get native classes, among other things. In that context,

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

class MyError extends Error {}

will work the way you expect.

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

For people not on Node 4/5, or recent Chrome only, you may want to consider using something like https://www.npmjs.com/package/error. You can also explore https://www.npmjs.com/package/babel-plugin-transform-builtin-extend. The approximateoption from that is the same behavior from Babel 5. Beware that the non-approximatebehavior is definitely edge-casey and may not work in 100% of cases.

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