Ik zie dat de operator instanceof
niet werkt op subklassen van Error
, wanneer deze wordt uitgevoerd onder babel-nodeversie 6.1.18/Node versie 5.1.0 op OS X. Waarom is dit? Dezelfde code werkt goed in de browser, probeer als voorbeeld mijn viool.
De volgende code voert true
uit in de browser, terwijl deze onder babel-node onwaar is:
class Sub extends Error {
}
let s = new Sub()
console.log(`The variable 's' is an instance of Sub: ${s instanceof Sub}`)
Ik kan me alleen maar voorstellen dat dit te wijten is aan een bug in babel-node, aangezien instanceof
werkt voor andere basisklassen dan Error
.
.babelrc
{
"presets": ["es2015"]
}
Gecompileerde uitvoer
Dit is het JavaScript samengesteld door babel 6.1.18:
'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));
Antwoord 1, autoriteit 100%
tl;dr Als je Babel 6 gebruikt, kun je https://www gebruiken .npmjs.com/package/babel-plugin-transform-builtin-extend
Uitbreiding van ingebouwde typen zoals Array
en Error
en dergelijke is nooit ondersteund in Babel. Het is perfect geldig in een echte ES6-omgeving, maar er zijn vereisten om het te laten werken die erg moeilijk te transpileren zijn op een manier die compatibel is met oudere browsers. Het “werkte” in Babel 5 in die zin dat het geen fout veroorzaakte, maar objecten die werden geïnstantieerd vanuit de uitgebreide subklasse werkten niet zoals ze zouden moeten, bijvoorbeeld:
class MyError extends Error {}
var e1 = new MyError();
var e2 = new Error();
console.log('e1', 'stack' in e1);
console.log('e2', 'stack' in e2);
resulteert in
e1 false
e2 true
Hoewel er geen fout is opgetreden, krijgt de subklasse niet de juiste ‘stack’ zoals fouten zouden moeten doen. Evenzo, als u Array
zou uitbreiden, zou het zich enigszins als een array kunnen gedragen en array-methoden hebben, maar het gedroeg zich niet volledig als een array.
De Babel 5-documentatie noemde dit specifiek als een randgeval van klassen om op te letten.
In Babel 6 zijn klassen gewijzigd om meer aan de specificaties te voldoen in de manier waarop subklassen worden afgehandeld, en een neveneffect daarvan is dat de bovenstaande code nu nog steedsniet zal werken, maar het zal wel niet op een andere manier werken dan voorheen. Dit is behandeld in https://phabricator.babeljs.io/T3083, maar ik zal hier ingaan op een mogelijke oplossing.
Om het gedrag van Babel 5 subklassen terug te geven (wat nog steeds niet goed of aanbevolen is), kun je de ingebouwde constructor in je eigen tijdelijke klasse plaatsen, bijvoorbeeld
function ExtendableBuiltin(cls){
function ExtendableBuiltin(){
cls.apply(this, arguments);
}
ExtendableBuiltin.prototype = Object.create(cls.prototype);
Object.setPrototypeOf(ExtendableBuiltin, cls);
return ExtendableBuiltin;
}
Met deze helper, in plaats van te doen
class MyError extends Error {}
doen
class MyError extends ExtendableBuiltin(Error) {}
In jouw specifieke geval heb je echter gezegd dat je op Node 5.x zit. Node 5 heeft ondersteuning voor native ES6-klassen zonder transpiling. Ik raad je aan die te gebruiken door de voorinstelling es2015
te verwijderen en in plaats daarvan node5
zodat je onder andere native lessen krijgt. In die context,
class MyError extends Error {}
werkt zoals u verwacht.
Voor mensen die geen gebruik maken van Node 4/5, of alleen recent Chrome, kun je overwegen iets als https://www te gebruiken .npmjs.com/package/error. U kunt ook https://www.npmjs.com/package/babel-plugin-transform- verkennen ingebouwde uitbreiding. De optie approximate
daarvan is hetzelfde gedrag als bij Babel 5. Pas op dat het gedrag dat niet approximate
is, absoluut edge-casey is en mogelijk niet in 100% van de gevallen werkt.
Antwoord 2, autoriteit 9%
instanceof
werkt niet voor fouten in subklassen als het compileerdoel is ingesteld op “es5”. Ik heb het doel ingesteld op “es6” in mijn tsconfig.json
en instanceof
produceerde het juiste resultaat.