弱小システム屋が使う技術メモと他色々

主に自分用な技術メモが多くなる気がする。他色々が書かれるかどうかは不明。

JavaScriptのclass構文を使って「ASUS」を読む

ほとんどネタ記事。
Twitterで「ASUS」の読み方の話題がトレンドに入っていたので、勢いでASUSの読み方を表示するJavaScriptを作った。

※ 下記の通り、読み方論争は公式には決着済の話。
「ASUS」読み方論争に決着 「エイスース」に統一 - ITmedia NEWS

ASUSを読むボタン

まずは見たほうが早いので、作った結果を。ランダムにASUSの読みを表示してくれる。
ECMAScript 2015依存なので動かないブラウザもあると思う。

ボタンを押すと、ここに「ASUS」の読みが出力される。

ボタン実装のコード

こんなかんじでJavaScriptを書いている。

/**
 * AsusTokenクラス
 * ASUSの文字(列)の読みと次に続くAsusTokenを定義
 */
class AsusToken {
  constructor() {
    // 配列で読み方の候補を定義する
    // 読み方は配列要素からランダムに選択される。
    this.reads = ['ダミー'];
    
    // 次のTokenを示す。
    // null の場合は終端のTokenであることを示す
    this.nextToken = null;
  }

  /*
   * 現在のトークンの読み方を取得(候補の中からランダムで取得)
   */
  get read() {
    return this.reads[Math.floor(Math.random() * this.reads.length)];
  }
}

class SToken extends AsusToken {
  constructor() {
    super();
    this.reads = ['ス'];
    this.nextToken = null;
  }
}

class SUToken extends AsusToken {
  constructor() {
    super();
    this.reads = ['サー', 'スー', 'サ'];
    this.nextToken = new SToken();
  }
}

class AToken extends AsusToken {
  constructor() {
    super();
    this.reads = ['エー', 'エイ', 'ア'];
    this.nextToken = new SUToken();
  }
}

/**
 * 文字列ASUSの読み方を取得する
 */
function getReadOfASUS() {
  var readAsus = '';
  
  // "A"のTokenから開始し、次のTokenが無くなるまで読みを結合
  var token = new AToken();
  while(token != null) {
    readAsus += token.read;
    token = token.nextToken;
  }
  return readAsus;
}

/**
 * 文字列ASUSの読み方を画面に表示する
 */
function showReadOfASUS() {
  document.getElementById('ASUSText').textContent = getReadOfASUS();
}

あとはHTMLにscript, 発火用のボタン, id="ASUSText"のテキスト要素を仕込む。

使われている要素:class

ECMAScript 2015で追加された構文。
Javaなどのクラス定義に慣れていると、functionやprototypeで定義する構文よりもこの書き方のほうがすっと入ってきそう。

実装や調査時こちらのページを参考にさせていただきました。
JavaScriptにもクラスがやってきた!JavaScriptの新しいclass構文をマスターしよう | HTML5Experts.jp
ES2015新機能: JavaScriptのclassとmethod - Qiita

対応状況

このあたりから確認できる。

執筆時点の対応状況はこんなところか。(各ブラウザの最新を利用している前提)

使えそう Edge, Chrome, FireFox, Opera, Safari, iOSSafari
使えなさそう IE, Androidブラウザ*1

Androidがダメってのが痛い。
広く一般への利用を求める場合、現時点では利用を避けたほうが良いのかも。

classに定義できるもの

コンストラクタ、getter, setter, メソッド定義など。

メンバ変数(プロパティ)を定義する構文はなさそう。
それっぽいものを定義する場合、コンストラクタでの初期化で定義するか、getter/setterを使って定義することになる。

個人的にはメンバの定義箇所が分散してほしくないので、コンストラクタで定義するほうが好み。

コンストラクタ

constructorの名称で定義するメソッドがコンストラクタになる。
super()と書けば、Javaの如く親クラスのコンストラクタを呼べる。
複数定義するとSyntax Errorとなる。

getter/setter

Javaのgetter/setterの先入観でちょっと戸惑った所。
使い方が異なる。とりあえずJavaとだけ比較するとざっくりの違いは下記の通り。

言語 使う時の書き方
Java 明確にメソッドを通じてデータを操作する書き方となる。
JavaScript 利用者から見ると、データを直接操作するような書き方となる。実体は定義したメソッドを通じてのデータアクセスとなる。


構文で比較するとこんな感じ。

言語 getterを使う時の構文 setterを使う時の構文
Java hoge = obj.getHoge(); hoge = obj.hoge;
JavaScript obj.setHoge("hoge"); obj.hoge = 'hoge';


JavaScriptは元々getXxx()setXxx()といったメソッドは作らない。
メンバにアクセスする場合は直接アクセスする。
(スコープでメンバ隠蔽するような構文もないし)

でもって、getter/setterも同じような形でアクセスできるようになっている。

サンプル

class Sample {
  constructor() {
    /* No def */
  }

  /* 
   * hogeプロパティがなくても、
   * hoge = sample.hoge; といった書き方をするとこのメソッドが呼ばれる.
   */
  get hoge() {
    return this._hoge;
  }

  /* 
   * hogeプロパティがなくても、
   * sample.hoge = 'fugafuga'; といった書き方をするとメソッドが呼ばれる.
   */
  set hoge(value) {
    this._hoge = value;
  }
}
メソッド定義

functionとか書かなくてもメソッドが定義できる。
あまり説明することは無いので、サンプルコードだけ。

サンプル

class Sample {
  constructor() {
    /* No def */
  }

  /* 
   * これでSampleクラスにexecメソッドが追加される。
   */
  exec(arg1, arg2) {
    /* 処理定義 */
  }
}
setter/getter/メソッド定義の補足

setter/getter/メソッド定義はclassと一緒に使うことが多そうだが、これらは短縮記述用の構文として別定義されているもの。
class構文を使わず、別の箇所で利用することもあるようだ。

参考:
Method definitions - JavaScript | MDN
setter - JavaScript | MDN
getter - JavaScript | MDN

まとめ

  • class構文でJavaScriptでクラス定義ができる。
  • 古めのブラウザを動作対象にしたい場合は微妙かも。*2
  • コードの見通し的に使えるなら使ったほうが幸せになれそう。
  • ASUSの正しい読みは「エイスース」。

*1:Android Browserと書いてあったけど標準ブラウザの話で、Chromeは別かもしれない。

*2:2017/05現在