R-SQUARE.net

研究開発部

JavaScript で クラスっぽい何か

クロージャとかいうわけわかめな仕組みを試す。

クロージャ?

あっちこっちでクロージャの説明を読むのだけれど、 かいつまんで言うと「こうだ」ってのがまとめられない。 グローバルを汚染しない、とか変数の衝突を避けるとか、そんな目的で使われるらしい。 関数リテラルを定義し、即呼び出すのが肝らしい。
下記の例で言うと
  1. moduleExporter 関数を定義する。(js_class_2.js2行目)
    1. moduleExporter 関数は引数として、オブジェクトと関数をとる。
  2. moduleExporter 関数を実行する。(js_class_2.js9行目)
    1. 第一引数としてグローバルオブジェクトを渡す。(js_class_2.js9行目)
    2. 第二引数として関数 moduleClosure を渡す。(js_class_2.js9〜47行目)
  3. moduleClosure の{}のなかでクラスっぽい関数を作って、それを返す。(js_class_2.js46行目)
  4. moduleExporter の{}のなかでは、グローバルオブジェクトのプロパティとして関数をセットしている。(js_class_2.js8行目)
  5. moduleClosure のなかで定義したクラスっぽい関数は名前空間にアクセスする風に実行できる。(js_class_2.html5行目)
こんな感じ?ほんと?

ソースコード

JavaScript (js_class_2.js)
//js_class_2.js
(function moduleExporter(global, closure){
  'use strict';

  if (!global.R2) {
    global.R2 = {};
  }
  global.R2.Test = closure();
}(((this || 0).self || global), function moduleClosure(){
  //コンストラクタ
  var Greeting = function(lang) {
    console.log('lang : ' + lang);
    if (!lang) {
      this.lang = 'ja';
    } else {
      this.lang = lang;
    }
  };
  Greeting.prototype = {
    //定数的な何か
    get GREETING_MESSAGE_EN() {return 'Hello, %name% !';},
    get GREETING_MESSAGE_FR() {return 'Bonjour, %name% !';},
    get GREETING_MESSAGE_JA() {return 'こんにちは、 %name% さん。';},
    get NONAME_EN() {return 'no name';},
    get NONAME_FR() {return 'sans nom';},
    get NONAME_JA() {return '名無し';}
  };

  //public method
  Greeting.prototype.hello = function(name) {
    if (!name) {name = this['NONAME_' + this.lang.toUpperCase()];}
    var m = getMessage(name, this);
    return m;
  };

  //private method
  var getMessage = function(name, parent) {
    console.log('name : ' + name);
    var g = parent['GREETING_MESSAGE_' + parent.lang.toUpperCase()];
    var regex = new RegExp("(\\s*\\w*\\s*)(%name%)(\\s*\\w*\\s*)");
    var ret = g.replace(regex,'$1' + name +'$3');
    return ret;
  };

  //コンストラクタを返す
  return Greeting;
}));
          


html (js_class_2.html)
<div id="main">
<!-- js_class_2.html -->
<script type="text/javascript">
var lang = (navigator.browserLanguage || navigator.language || navigator.userLanguage || 'ja').substr(0, 2);
var ts = new R2.Test(lang);
var helloTest = function(event) {
  var yourname = $('input#yourname').val();
  var res = ts.hello(yourname);
  $('#result').prepend('<' + 'p>' + res + '<' + '/p>');
};
$(document).ready(function() {
  $('button#hello').click(helloTest);
});
</script><p><input type="text" id="yourname" placeholder="あなたの名前"><button id="hello">hello</button></p>
<div id="result"></div>
</div>          


動作例



まとめ

  • とりあえずこうなのか?これでいいのか?ようわからん。
  • 各ブラウザがES6をサポートするようになったら、こういうトリッキーなのは使わないで済むのか?


last modified : 2015-11-26T19:10:33+09:00