Can't subclass with ES6 / babel-node

2019-09-13 19:00发布

问题:

I have the following files: gist

The index.js attempts instantiate a base "Auth" class but in it's constructor the auth class acts as an object factory and passes back a subclass of Auth instead.

'use strict';
import Auth from './Auth';

let o = new Auth({type:'Oauth1'});
console.log(o);
o.getToken();

The Auth.js class definition is as follows:

'use strict';
import Oauth1 from './Oauth1';

export default class Auth {
    constructor(config) {
        if (this instanceof Auth) {
            return new Oauth1(config);
        } else {
            this.config = config;
        }
    }

    getToken() {
        console.log('Error: the getToken module must be implemented in the subclass');
    }
}

And the Oauth1.js class definition is:

'use strict';
import Auth from './Auth';

export default class Oauth1 extends Auth {
    getToken() {
        console.log('Auth: ', Auth);
    }
}

When running with babel-node index.js I get the following error:

TypeError: Super expression must either be null or a function, not undefined

at _inherits (/repos/mine/test-app/Oauth1.js:1:14)
at /repos/mine/test-app/Oauth1.js:4:28
at Object.<anonymous> (/repos/mine/test-app/Oauth1.js:4:28)
at Module._compile (module.js:434:26)
at normalLoader (/usr/local/lib/node_modules/babel/node_modules/babel-core/lib/api/register/node.js:199:5)
at Object.require.extensions.(anonymous function) [as .js] (/usr/local/lib/node_modules/babel/node_modules/babel-core/lib/api/register/node.js:216:7)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Module.require (module.js:365:17)
at require (module.js:384:17)

If I remove the extends expression from the Oauth1 class it executes but then I am not getting the inheritance I want.

回答1:

Your issue has nothing to do with babel. The real problem is that you have circular dependencies in your code.

To resolve this issue you should remove Oauth1 dependency from its parent Auth class:

'use strict';
export default class Auth {
    constructor(config) {
        this.config = config;
    }

    getToken() {
        console.log('Error: the getToken module must be implemented in the subclass');
    }
}
'use strict';
import Auth from './Auth';

export default class Oauth1 extends Auth {
    getToken() {
        console.log('Auth: ', Auth);
    }
}

If you don't want to remove this instanceof Auth check from your base class, you could require your Oauth1 subclass in run-time instead of importing it during module initialization:

constructor(config) {
    if (this instanceof Auth) {
        let Oauth1 = require('./Oauth1');
        return new Oauth1(config);
    }
    this.config = config;
}