web-dev-qa-db-ja.com

babel-nodeの下のErrorサブクラスのインスタンスでinstanceofが機能しないのはなぜですか?

babel-node version 6.1.18/Node version 5.1.0の下で実行すると、instanceof演算子がErrorサブクラスのインスタンスで機能しないことがわかりました。 OS Xで。これはなぜですか?同じコードがブラウザでうまく機能します。例として fiddle を試してください。

次のコードはブラウザに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}`)

instanceofError以外の基本クラスで機能するため、これはbabel-nodeのバグが原因であるとしか想像できません。

.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));
73
aknuds1

tl; dr Babel 6を使用している場合は、 https://www.npmjs.com/package/babel-plugin-transform-b​​uiltin-extend を使用できます

ArrayErrorなどの組み込み型の拡張は、Babelではサポートされていません。実際の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では、サブクラスの処理方法がより仕様に準拠するようにクラスが変更され、その副作用として、上記のコードはstill動作しませんが、以前とは異なる方法で動作しません。これは https://phabricator.babeljs.io/T308 で説明されていますが、ここでは解決策の可能性について詳しく説明します。

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 を使用して、ネイティブクラスなどを取得することをお勧めします。

class MyError extends Error {}

期待どおりに機能します。

Node 4/5、または最近のChromeのみ、 https:// www。 npmjs.com/package/errorhttps://www.npmjs.com/package/babel-plugin-transform-b​​uiltin-extendapproximateオプションはBabel 5と同じ動作です。non_approximate動作は間違いなくEdge-caseyであり、100%のケースでは動作しない可能性があることに注意してください。

87
loganfsmyth