Instanceof using class ES6 Inheritance does not work

Using the ES6 class syntax, I wonder why the instanceof operator does not work for the inheritance chain when there is an entire inheritance chain?

(not necessary)

How does instanceof operator work?

In obj instanceof Constructor the instanceof operator checks to see if the 'prototype' property of the Constructor function is present in the obj prototype chain. If present, return true . Otherwise false .


In the following snippet, a BTError inherited from Error ( 1. ) and SomeError continues from BTError ( 3. ). <w> But, as can be seen from ( 4. ), the instanceof operator shows false for new SomeError() instanceof BTError , which, in my opinion, should be true .

 class BTError extends Error {} console.log('1.', Reflect.getPrototypeOf(BTError.prototype) === Error.prototype); // 1. true console.log('2.', new BTError() instanceof Error); // 2. true console.log(''); class SomeError extends BTError {} console.log('3.', Reflect.getPrototypeOf(SomeError.prototype) === BTError.prototype); // 3. true console.log('4.', new SomeError() instanceof BTError); // 4. false console.log(''); class SpecificError extends SomeError {} console.log('5.', Reflect.getPrototypeOf(SpecificError.prototype) === SomeError.prototype); // 5. true console.log('6.', new SpecificError() instanceof Error); // 6. true console.log('7.', new SpecificError() instanceof BTError); // 7. false console.log('8.', new SpecificError() instanceof SomeError); // 8. false 

Question

Is there something non-trivial that I cannot understand, or is the instanceof operator just acting weird?

+5
source share
1 answer

Focusing on the last part of your example

You convert this code using BabelJS to make it compatible

 class BTError extends Error {} class SomeError extends BTError {} class SpecificError extends SomeError {} console.log('6.', new SpecificError() instanceof Error); console.log('7.', new SpecificError() instanceof BTError); console.log('8.', new SpecificError() instanceof SomeError); 

This is the passed version of the code above

 '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 BTError = function(_Error) { _inherits(BTError, _Error); function BTError() { _classCallCheck(this, BTError); return _possibleConstructorReturn(this, (BTError.__proto__ || Object.getPrototypeOf(BTError)).apply(this, arguments)); } return BTError; }(Error); var SomeError = function(_BTError) { _inherits(SomeError, _BTError); function SomeError() { _classCallCheck(this, SomeError); return _possibleConstructorReturn(this, (SomeError.__proto__ || Object.getPrototypeOf(SomeError)).apply(this, arguments)); } return SomeError; }(BTError); var SpecificError = function(_SomeError) { _inherits(SpecificError, _SomeError); function SpecificError() { _classCallCheck(this, SpecificError); return _possibleConstructorReturn(this, (SpecificError.__proto__ || Object.getPrototypeOf(SpecificError)).apply(this, arguments)); } return SpecificError; }(SomeError); console.log('6.', new SpecificError() instanceof Error); // 6. true console.log('7.', new SpecificError() instanceof BTError); // 7. false console.log('8.', new SpecificError() instanceof SomeError); // 8. false 

I think the problem is with the _inherit method, which directly binds to subClass.prototype not to superClass.prototype , but to an object created by merging this and another set of default properties.

With this prototype chain, inheritance will work, but the instanceof operator will not be able to move it by reference, and so you will get false , where you expect true .

Apparently, according to this bug report , this known and expected behavior (i.e. limitation) and a possible workaround is to use babel-plugin-transform-builtin-extend

+3
source

Source: https://habr.com/ru/post/1263868/


All Articles