<   2016年 01月 ( 40 )   > この月の画像一覧

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;
}
};
})();


[PR]
by tnomura9 | 2016-01-31 12:15 | 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 { ... }
}

便利そうでしょう。

[PR]
by tnomura9 | 2016-01-30 10:49 | 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 の本質は単純性だ。しかし、その単純さゆえに、変幻自在の変化を見せてくれる。

[PR]
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>

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

[PR]
by tnomura9 | 2016-01-29 22:50 | JavaScript | Comments(0)

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


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

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

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


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

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


[PR]
by tnomura9 | 2016-01-29 13:15 | Comments(2)

var foo = function (x) { ... } の効用

関数を定義するのに funnciton foo(x) { ... } ではなく var foo = function (x) { ... } という記法を取るのは奇を衒っているようにも見えるが、コードの可読性を上げる意味もある気がする。次のようなコードを書いてみた。

var square = function (x) {return x*x };
var add = function (x,y) {return x+y };
var sumOfSquares = function (x) {return x.map(square).reduce(add) };

このコードで、function キーワードの後ろを読めば、引数と関数の内容が一目瞭然だ。また、var キーワードの後ろを見ると、関数名の一覧になっている。まるで、Haskell のタイプシグネチャーのような読み方ができる。= function を -> のような記号と考えればいいのだ。

単純な関数だけでなく、次のような手続き的なコードも同じ利点がある。

var sumUpTo = function (x) {
var total = 0;
for(i=1;i<=x;i++) {
total += i;
}
return total;
}

この場合も var キーワードの後ろは関数名。function の直後は引数リスト。return される値は、この処理の結果を表している。

この書き方の利点はもう一つある。} の後で改行すれば、あの邪魔な ; が省略できるのだ。例えば次のようなコードもきちんと動く。

var square = function (x) {return x*x }
var add = function (x,y) {return x+y }
var sumOfSquares = function (x) {return x.map(square).reduce(add) }

コードの記述を上の方式で統一すれば、; をかなり見ないで済む。

また、これらの関数の中に現れる変数の前には必ず var キーワードを置くようにすれば、上の関数は綺麗にカプセル化される。統一した記法で、安全なプログラムが書ければ気持ちがいい。

次のコードは ; がないが、きちんと動いた。

var total = function (x) {
var total = 0
for(i=1;i<=x;i++) {
total += i
}
return total
}

a_lert( total( 10 ))

これから、JavaScript のコードは意識的に var foo = function (x) { ... } で書いてみることにする。

追記

JavaScript の文末には必ず ; (セミコロン)を置くことが勧められているのでそのようにしていたが、JavaScript には ASI (Auto Semicolon Insertion) 機能があるので、たいていの場合セミコロンは省略できるらしい。しかし、JavaScript の仕様では return, throw, break, continue, ++, — という Restricted Production の前後では改行が禁止されているためそれらの前後で改行すると意図とは違う箇所にセミコロンが挿入される場合がある。そのため文末のセミコロンは省略しないことを勧められているらしい。

しかし、これもエキスパートの間でもセミコロンをつける派とつけない派があり大論争になっているようだ。


個人的には、Ruby や CoffeeScript などで行末にセミコロンをつけないのが喜ばれているし、つけない派でいいのではないかと思う。プログラムを一気に作ってデバッグすることはないので、おかしな動作はデパッグの中ではじき出されるだろう。セミコロン派の人にコードを渡す時は、エディタの正規表現置換で行末にセミコロンを追加すればいい。行末にセミコロンがあるのは汚く見えるし、余計なキー入力はしたくない。今日からセミコロンつけない派になることにする。

ASI のパーサーを改良すればいいだけの話のような気もするが。

追記2

Restricted Production 以外に 関数定義 var foo = function () {} の後に無名関数の即時実行 (function (){..}()) が続いたりするとそれが引数と解釈される場合があるので曖昧なコードを書くときは空行で区切るか、セミコロンを使用したほうがいいらしい。これは文法というより、表現の曖昧性の問題だろう。好みはあるかもしれないがクロージャーを記述するときは先頭にセミコロンを置いて

;(function() { ... })()

としたらそのコードがクロージャーを記述している目印にもなるのではないか。あまりきれいな表現ではないが。または、クロージャーを書くときはかならず空行を挟むようにしたほうがきれいかもしれない。

[PR]
by tnomura9 | 2016-01-29 05:22 | Comments(2)

The Revealing Module Pattern

The Revealing Module Patten という JavaScript のデザインパターンがあるらしい。前回の記事ではローカル関数を隠蔽するために。クロージャーを使ったが、関数の即時実行で無名オブジェクトを返す方法だ。このデザインパターンでは、戻り値のオブジェクトの属性の値を公開したい関数にする。利点としては、

1. 開発者にクリーンなライブラリを提供できる
2. 隠蔽したデータを利用できる
3. グローバルの名前空間を汚さない
4. 関数や変数をローカルにして隠蔽できる
5. スクリプトの書き方を統一できる(ユーザ側で)
6. 公開されるメソッドがはっきりしているので、コードが読みやすくなる

欠点は、

1. 隠蔽されたローカル関数にアクセスできない
2. ローカル関数のオーバーライドができない

などだ

https://carldanley.com/js-revealing-module-pattern/ のコード例には次のようなものが掲げてあった。

var MyModule = ( function( window ) {
function myMethod() {
a_lert( 'my method' );
}
function myOtherMethod() {
a_lert( 'my other method' );
}
// explicitly return public methods when this object is instantiated
return {
someMethod : myMethod,
someOtherMethod : myOtherMethod
};
} )( window );

// example usage
MyModule.myMethod(); // undefined
MyModule.myOtherMethod(); // undefined
MyModule.someMethod(); // alerts "my method"
MyModule.someOtherMethod(); // alerts "my other method"

公開されるメソッドは MyModule オブジェクトの MyModule.someMethod と Mymodule.someOtherMethod で プライベートな myMethod や myOtherMethod は外部からは利用できない。

このような特定の目的を持ったコードの書き方を JavaScript デザインパターン というそうだが、それらをたくさん知っていると、随分コードの開発が楽になるのだろう。どうやら、JavaScript の文法を理解しただけでは JavaScript 使いにはなれないようだ。

どの分野もそうだが、JavaScript も奥が深そうだ。大変だ。

追記

このデザインパターンを使ってコードを書いてみたが、ローカル変数にアクセスできないのでデパッグがやりにくかった。開発の時は普通にグローバル空間でコードを書いて、最後にクロージャーでカプセル化するのが良いようだ。

[PR]
by tnomura9 | 2016-01-29 02:44 | JavaScript | Comments(0)

ローカル関数

JavaScript で無名関数を使いたいことが多いが、無名関数を記述するのに function() { ... } と書くとやたらと fundtion キーワードが増えて煩わしい。しかし、いちいち関数に名前をつけていると、名前空間を不必要に汚してしまう。そういう時は、ローカル関数を使うといい。関数の中で定義されたローカル関数は関数の実行が済むと消滅してしまう。

var squareAndSum = function(x) {
var square = function (x) {return x*x};
var add = function (x,y) {return x+y};
return x.map(square).reduce(add);
}

a_lert(squareAndSum([1,2,3]));

この方法では squareAndSum 関数を呼び出すたびに squre 関数と add 関数が再定義されるので squareAndSum 関数のオーバーヘッドが気になる場合は、次のようにクロージャーを使うといい。クロージャーは関数を戻り値として返す関数だが、クロージャーの戻り値の関数は、クロージャーの中のローカル関数を利用できる。

var squareAndSum = (function() {
var square = function (x) {return x*x};
var add = function (x,y) {return x+y};
return function(x){return x.map(square).reduce(add)}
})();

a_lert(squareAndSum([1,2,3]));


[PR]
by tnomura9 | 2016-01-28 05:23 | JavaScript | Comments(0)

function foo() { ... } と foo = function() { ... }

最近 var foo = function() { ... } という記述をよく見かけるようになった。function foo() { ... } と同じ意味になるのだが、どちらかというと前者の方が好みだ。無名関数を変数に代入することによって、関数も他の値と同じように他の関数の引数にできるのだというイメージが湧いてくる。

たとえば Array.prototype.map 関数を使う時に、次のようなコードが自然にかけるのがいい。map の引数の中に function() { ... } と入らないのがすっきりする。

> var square = function(x) {return x*x};

[Function]

> [1,2,3].map(square)

[ 1, 4, 9 ]


JavaScript の表現力の秘密が、関数が first order object であるということがよくわかる。


ふと思いついたのだけれど、無名関数の省略形を (..) { ... } にしたら、function キーワードが要らなくなるのではないだろうか。これだと関数は全て、


var foo = (x) { ... }


で定義できる。


[PR]
by tnomura9 | 2016-01-27 06:24 | Comments(0)

CoffeeScript の気になるところ

CoffeeScript の日本語の解説を見つけた。


これを読んで CoffeeScript の仕様で気になる点が2、3あったので書いてみる。

1. CoffeeScript は JavaScript の単なる略記法ではなく、制御文などに CoffeeScript 独特なものがあるということ。たとえば CoffeeScript には for 文がない。制御文に微妙な違いがあると、JavaScript と CoffeeScript の間で混乱が起きやすいのではないかと思う。制御文の機能については、表現は様々でも、言語間でそれほど違いが発生しないのだから、わざわざ新しい制御文を作ることは混乱を引き起こすのではないかと思う。

2. 関数の引数のカッコを省略したこと。これは Haskell の方法を取り入れたのかもしれないが、Haskell の場合は関数の取り扱い方が JavaScript とは異なっている。Haskell では関数の出力をパイプラインのようにつないでいくというプログラミングスタイルになるので、手続き型言語のスタイルを取る JavaScript の関数の取り扱い方とは異なっている。カッコをスベースに置き換えることで、入力の手間はそう増えないのだから、CoffeeScript でコーディングする場合も、関数の引数はカッコで囲んだ方がいいと思う。

3. グローバル変数の名前は、ローカル変数には使えなくなったこと。これは関数の内容の隠蔽にあまり良くない影響を与えるのではないだろうか。関数の内部を記述するのに、いちいち外部のグローバル変数の名前を気にしなくてはならないのは気持ちが悪い。

4. 関数の最後の文の戻り値が必ずその関数の戻り値として戻されている。これは、余分な工夫のように思える。戻り値を指定したい時は、明白に return 文を記述すれば問題はないのだけれど、自分の意図しないところで、コードが作られるのは気持ちが悪い気がする。

やはり、CoffeeScript を単なる JavaScript の略記法と考えるのは、無理なようだ。JavaScript でコードを記述する時よりは、明らかにバグの発生が少なく、可読性が向上すると思われるし、プロジェクトの開発に CoffeeScript が指定されている場合あるようだ。しかし、その場合も全く新しい言語を学習するくらいのつもりで取り組んだ方がいいのではないかと思う。


[PR]
by tnomura9 | 2016-01-27 06:07 | JavaScript | Comments(0)