引数に応じて親クラスを切り替えたいことがあって調べて、Dynamic super classes (extends) in ES6 – MikeDoesWeb が出てきたので試した。
おそらく私はmix-inみたいなことをしたかったのだと思う。
サンプルコードとそれのテスト(使い方の例になると思う)はGitHubに置いた。
解決法の解説/概要
クラスを直接定義するのではなく、関数スコープ内で定義することで解決していた。
実際に私がやりたかったのはNode.jsで動くならfs
を使うクラスを継承して、ブラウザで動くならBrowserFS
を使うクラスを継承したかった。
外からみると同じAPIにしたかったので、環境か引数によって必要なバックエンドのクラスを切り替えてテストしたかった。
以下GitHubに置いた解決策の抜粋。
// fsを使うクラス export class FS { constructor(config){ } } // BrowserFSを使うクラス export class BrowserFS { constructor(config){ } } // fallbackクラス export class DefaultClass { constructor(config){ } }; // 外からはこの擬似クラス(実態は関数)を使う const Dynamic = function(config = {}){ if(!new.target){ throw "Uncaught TypeError: Class constructor Dynamic cannot be invoked without 'new'"; } // Dynamicというクラスを引数に応じて定義する if(config.backend === 'fs'){ // FSを継承するパターン class Dynamic extends FS { constructor(config){ } }; return new Dynamic(config); } if(config.backend === 'browserfs'){ // BrowserFSを継承するパターン class Dynamic extends BrowserFS { constructor(config){ } }; return new Dynamic(config); } // fallback return new DefaultClass(config); }; export default Dynamic;
es6-dynamic-class-extends/dynamic.js at master · peccu/es6-dynamic-class-extends · GitHub
使用法はテストコードでイメージできるかと。 (Jest利用、同じく抜粋)
Dynamic
はクラスではなく関数なので、instanceof Dynamic
はfalseとなる。
import {default as Dynamic, FS, BrowserFS, DefaultClass} from './dynamic'; describe('Dynamically switching parent class', () => { test('non specified class', () => { let target = new Dynamic(); expect(target).toBeInstanceOf(DefaultClass); }); test('extends FS', () => { let target = new Dynamic({backend: 'fs'}); expect(target).toBeInstanceOf(FS); }); test('extends BrowserFS', () => { let target = new Dynamic({backend: 'browserfs'}); expect(target).toBeInstanceOf(BrowserFS); }); });
es6-dynamic-class-extends/dynamic.test.js at master · peccu/es6-dynamic-class-extends · GitHub
c.f.
environment
.babelrc
{ "presets": ["@babel/preset-env"], "plugins": [ [ "@babel/plugin-transform-runtime", { "regenerator": true } ] ] }
package.json
... "scripts": { "test": "jest" }, "devDependencies": { "@babel/core": "^7.2.2", "@babel/plugin-transform-runtime": "^7.2.0", "@babel/preset-env": "^7.2.3", "@babel/runtime": "^7.2.0", "babel-core": "^7.0.0-bridge.0", "babel-jest": "^23.6.0", "jest": "^23.6.0" }, ...