人気ブログランキング | 話題のタグを見る

The Singleton Pattern

JavaScript のデザインパターンに興味が湧いたので Addy Osmani の


を読み始めた。大規模なアプリケーションの開発などはやったことがないので、誤解も多いかもしれないが、プログラムの抽象的な構造を知るというところにポイントを置いて読んでみることにした。

紹介されているデザインパターンの最初は The Module Pattern だったので省略する。2番目のデザインパターンは The Singleton Patten だった。シングルトンパターンはデザインパターンの中でも最もよく使われているものらしい。シングルトンパターンのクラスからインスタンスを作ると、1個のオブジェクトしかできない仕組みだ。いろいろなオブジェクトから使い回しするようなクラスで、インスタンス化のコストが大きかったり、グローバル変数の代わりにクラス間の通信に使われたりするらしい。

原著のサンプルコードのエッセンスを抜き出したものを次に示す。

var mySingleton = (function () {
var instance;
function init() {
function privateMethod(){
console.log( "I am private" );
}
var privateVariable = "Im also private";
var privateRandomNumber = Math.random();
return {
publicMethod: function () {
console.log( "The public can see me!" );
},
publicProperty: "I am also public",
getRandomNumber: function() {
return privateRandomNumber;
}
};
};
return {
getInstance: function () {
if ( !instance ) {
instance = init();
}
return instance;
}
};
})();
// Usage:
var singleA = mySingleton.getInstance();
var singleB = mySingleton.getInstance();
console.log( singleA.getRandomNumber() === singleB.getRandomNumber() ); // true

mySingleton クラス(JavaScript にはクラスの概念はないので実際はオブジェクトリテラルだが)から getInstance() 関数で mySingleton クラスのインスタンスを作る。しかし、mySingleton クラスのコンストラクタである init() 関数はプライベートになっている。

トリックの中心は、赤字の部分で、getInstance() 関数が呼ばれた時、プライベート変数の instance がオブジェクトを持っていなければ、init() 関数を呼んでオブジェクトを instance 変数にバインドし、すでに instance 変数にオブジェクトがバインドされていれば、そのオブジェクトを返す。これによって、mySingleton クラスのインスタンスは1個だけが生成されることになる。

instance 変数はグローバル変数ではないが、クロージャーによって値が保存されているところもトリックのひとつだ。名前空間を汚染することなく、値(状態)を保持できている。どうもデザインパターンではクロージャーの活用がカギになっているような気がする。

シングルトンパターンは頻用されているが、用途が誤っていたり、使いすぎに注意する必要があるらしい。


ついでにシングルトンパターンのマクロの記述を考えてみた。

#singleton("mySingleton") {
private_variables: { }
public_object: { }
}

あるいは singleton という名前で次のようなスニペットにしてもいいかもしれない。instance 変数と init() 変数は private なので名前を変える必要がない。getInstance() もシングルトンクラスのインスタンスを作る関数をこの名前で統一すれば、mySingleton のところだけを変えればいい。

// The Singleton Pattern
var mySingleton = (function () {
var instance;
var init = function () {
//private variables

return {
//public properties

};
};
return {
getInstance: function () {
if ( !instance ) {
instance = init();
}
return instance;
}
};
})();


# by tnomura9 | 2016-01-31 12:15 | JavaScript | Comments(0)

究極の AltJS

数多存在する AltJS のなかで自分も究極の JS を考え見た。まず、function キーワードを追放して関数は無名関数だけにして表記を (x) { ... } にする。また、変数は原則ローカル変数としグローバル変数のみ定義の時に global 指定する。関数の定義は次の形式に統一する。

foo = (x) { ... }

行末のセミコロンは廃止。1行に複文を記述するときのみ区切り記号として使用。

制御構造のキーワードには一切手を加えない。しかし、マクロとしてデザインパターンをあらわすキーワードを利用可能にする

たとえば、

#class Foo {
private bar, baz
public hoge, fuga
...
}

#closure {
...
...
return_function (x) { ... }
}

#reveal {
...
...
return_obj { ... }
}

便利そうでしょう。

# by tnomura9 | 2016-01-30 10:49 | JavaScript | Comments(0)

JavaScript の魅力

最近 JavaScript が面白くて仕方がない。探せば探すほど、いろいろなトリックに出会えるし。コードが自由自在に変化する。Ruby の時は、オブジェクト志向プログラムという理解しがたい概念が、Ruby でコードを作ることで、簡単に体感できるのに驚いたり喜んだりしたのだが、JavaScript の場合は、発想のシンプルさと応用範囲の広さに驚かされる。

JavaScript がこれほど人を引き付けるのは、記法のいけてなさにもかかわらず、いろいろな発想を受け入れる懐の深さがあるからだ。プログラム言語の能力が、プログラムの表記法だけでは判断できないことがわかる。

JavaScript のこの表現力の源泉は、一つは関数が 1st class citizen である事。つまり、文字列や数値と同じように一つのものとして扱って、高階関数の引数として使える事だ。高階関数の威力は Haskell を学び始めた時に、map 関数に感動した事で体感した。

map (*2) [1..10]

JavaScript もこのような高階関数の威力を十分に活用出来る仕様になっている。次の例は Array.prototype.map 関数だが、このような備え付けの関数だけでなく、実際には自在に高階関数を記述する事ができる。

[1,2,3,4,5].map(square)

Haskell には高階関数を活用してシンプルにパーサーを作成できるライブラリがあるが、JavaScript でもそのような事が可能だと思う。

もう一つの JavaScript の特徴は、オブジェクトが基本的に {key1: valu1, key2: valu2, ,.. } というようなオブジェクトリテラルであるということだ。Ruby や Java などの整備されたオブジェクト指向言語とは違い、かなり原始的な定義だが、それゆえに、あらゆるものをオブジェクトに包み込んでしまうことができる。通常のクラスとはやや毛色の違うものもオブジェクトとしてカプセル化できてしまう。

これが、JavaScript についての様々なハックが現れてくる理由だろう。

JavaScript の特色を考えると、1st class citizen としての関数と、オブジェクトリテラルとしてのオブジェクトに、どのような言語にもある制御構造を装備したものと考えることができる。この構成は Lisp に似て、非常に単純な構成だ。Lisp の文法規則は呆れるほど少ない。しかし、Lisp/Scheme で書けないプログラムはない。この簡潔性を JavaScript も持っているようだ。

JavaScript の本質は単純性だ。しかし、その単純さゆえに、変幻自在の変化を見せてくれる。

# by tnomura9 | 2016-01-30 07:46 | JavaScript | Comments(0)

正規表現で行末のセミコロンをつける

JavaScript のセミコロンを行末につけないコードの行末にセミコロンをつけるのは、正規表現を使うと簡単にできるような気がする。行末にセミコロンをつける関数 sclnify(x) は次のようになる。

var sclnify = function (x) { return x.replace(/([^{])\n/, "$1;\n") }

このくらいの正規表現なら vim ですぐに置き換えができる。ついでに、HTML のプログラムを作ってみた。テキストエリアにセミコロンのないプログラムを書いて、click me ボタンをクリックすると行末にセミコロンをつけてくれる。また { が行末にある場合はセミコロンはつかない。

<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<textarea name="" id="target" cols="30" rows="10"></textarea>
<input type="button" value="click me" o_nclick="sclnify()">
<script>
var target = d_ocument.getElementById("target")
var sclnify = function() {
str = target.value
target.value = str.replace(/([^{])\n/g, "$1;\n")
}
</script>
</body>
</html>

セミコロンつけない派とつける派の間の距離はそう遠くないような気がする。

# by tnomura9 | 2016-01-29 22:50 | JavaScript | Comments(0)

JavaScript の セミコロンを省略する派


という記事を読んでみたら、2、3の点だけ注意したら JavaScript のセミコロンは省略できるらしい。
注意点というのは、入門者だったら次の2点くらいで意図しない動作は防げるようだ。

1. return の後は改行しない
2. ( や [ や { で始まる文の先頭には ; をつける

理由は、次の記事に書かれている。


これくらいのルールでセミコロンを省略できるのなら、やってみたい気がする。

セミコロンいらない派の主張はこうである。「ちょっとの工夫で不都合が起きないのならセミコロンはいらないではないか。」また、セミコロン必須派の意見はこうである。「セミコロンを付けるだけで不都合が避けられるのだからつけるべきではないか」しかし、どちらもどの方法が実際にバグを防いだのかあるいは発生させてしまったのかについてはだれも検討していない。


# by tnomura9 | 2016-01-29 13:15 | JavaScript | Comments(2)