FJCT_ニフクラ mobile backend(mBaaS)お役立ちブログ

スマホアプリ開発にニフクラ mobile backend(mBaaS)。アプリ開発に役立つ情報をおとどけ!

JavaScriptのクラスを動的に作成する

f:id:mbaasdevrel:20171212211252p:plain

現在、非公式のReact Native SDKを作っているのですが、公式JavaScript SDKがES5ベースで作られているのに対して、React Native SDKはTypeScript/ES6ベースになっています。

一番大きな違いとしてはクラスを使って構築されていることです。その動作差異で苦労した点を紹介します。

やりたいこと

JavaScript SDKのようにデータストアのクラスを生成し、そのインスタンスで行のデータを作りたい。

const Item = ncmb.DataStore('ReactNative');
const item = new Item(); // ここ!
item
    .set('msg', 'Hello World')
    .save()
    .then((data) => {
    })

これを実現しようと思うと、DataStoreクラスのクラス名に ReactNative というラベルを持たせる必要があります。

クラス変数について

JavaScriptのクラスにはクラス変数(スタティック変数)がありません。TypeScriptでは実現できているのですが、これはクラス全体で共有されてしまいます。

class Hoge {}
const aa = Hoge;
const bb = Hoge;
aa.test = 'test1';
bb.test = 'test2'
console.log(aa.test) // -> test2

そのため、クラス変数に持たせることができません。

解決策1:evalを使う

evalを使って動的にクラスを作成する方法があります。

const getDataStore = (name) => {
  const d = eval(`class ${name} extends DataStore {
    constructor() {
      super();
      this.className = ${name}.className;
    }
  }`);
  d.className = name;
  return d;
}

const Item1 = getDataStore('Item1')
const Item2 = getDataStore('Item2')
const item = new Item1();

console.log(item.className); // -> Item1

この方法はNode.jsであれば問題ないのですが、React Nativeの場合はevalを別な環境(blob上)で行うようで、DataStoreクラスがないというエラーが出てしまいます。

解決策2:関数を使う

そこで考えたのが継承を使う方法です。DataStoreを継承したクラスを定義した場合、クラス変数は別空間で管理されます。また、関数の中でクラスを継承して返却する場合、クラス名は動的でなくとも構いません。

DataStore = (name?: string) => {
  if (!name) {
    throw new Error('Please set the className')
  }
  return class Data extends DataStore {
    static ncmb = this
    constructor(fields?: object) {
      super(Data.ncmb, fields)
      this.className = name
    }
  }
}

この方法であれば、動的にクラス変数を変えつつ、JavaScript SDKと同じような動作が実現できます。

まとめ

今回の方法を使えば、JavaScript SDKもクラスベース(ES6ベース)にするのもさほど難しくなさそうです。クラスになれば継承も容易になりますし、JavaScript SDKの拡張もしやすくなるでしょう。

中津川 篤司

中津川 篤司

NCMBエヴァンジェリスト。プログラマ、エンジニアとしていくつかの企業で働き、28歳のときに独立。 2004年、まだ情報が少なかったオープンソースソフトの技術ブログ「MOONGIFT」を開設し、毎日情報を発信している。2013年に法人化、ビジネスとエンジニアを結ぶDXエージェンシー「DevRel」活動をスタート。