for文の二重ループを一重ループにする方法


一重ループという言葉が正しいのかどうかはともかく、for文の二重ループをfor文一つだけにする方法についてメモとしてJavaScriptのコードで書きます。

プログラマのためのコードパズル ~JavaScriptで挑むコードゴルフとアルゴリズムを呼んで知った方法。といっても、方法は単純なので、やり方を知った今となってはなぜ今まで思いつかなかったんだろうとさえ思う。

2次元配列を探索する場合、たいていの場合は二重ループを使うことが多いと思います。例えば、九九を一の段から順番に探索していって、初めて50以上になった掛け算のみ出力するというプログラムを書こうと思った場合、二重ループを使うと下記のようになります(もっと実用性のあるプログラムを思いつけばよかったのですが、思いつきませんでした・・・。後、見つからなかった場合の判定もしていません)。

このように二重ループで書いた場合、全く同じbreak文の判定条件文を2回書かなければいけません。しかし、これを一重ループにすることにより、breakの判定条件文を1回だけですますことができます。例えば下記のような感じ。

for文の継続条件はiについて書いているのにたいし、for文の中のカウンタ変数の更新はjのみについて書いています。そうして、iについてはj+1が9未満にならない(つまり9以上)になる時にカウントするようにし、その時jは次のループで0になるように-1に変更します。これでループ一つだけで、2次元配列を探索し、breakの条件判定文も一つだけですむようになりました。

一見、何をしてるのか分かりにくいんですけどね。ただたんにbreakの判定条件を一つだけにしたいなら、関数化するほうが分かりやすいかもしれません。

2016/10/16追記:
二重ループを抜けるのには、ラベル構文というものを使ったほうがいいかもしれません(JavaScriptで多重ループを抜けるラベル構文について | while(isプログラマ))。

JavaScriptでnew演算子をつけずにコンストラクタを実行する


またオブジェクト指向JavaScriptの原則で知った方法。実際に使うことはないと思うのだけど、こういう方法もあるのかと思ったので。

こんな感じでnew演算子をつけないとオブジェクトが作成されませんし、グローバルオブジェクト(ブラウザの場合はwindow)を汚染してしまいます。

でも、ArrayやRegExpのオブジェクトはnewをつけなくてもオブジェクトが作成されるみたいです。

このようにnew演算子を使わずにオブジェクトを生成する方法としては、下記のようにinstanceof演算子を使えばできるとのこと。

つまり、thisがPersonか調べて、falseならばnew演算子をつけた自分自身を返すというような感じです。再帰みたいな感じですね。これは思いつきませんでした。

ちなみに、こういうコンストラクタを『スコープセーフなコンストラクタ』というようです。ただ、『スコープセーフ』で検索してもJavaScript関連のページがほとんどヒットしない(ヒットしても『オブジェクト指向JavaScriptの原則』の紹介ページ)ので、日本ではあまり一般的な呼び方ではなさそうです。

アメリカとかだと使われてる言葉なのだろうか? 英語で検索してみると下記のページがヒットしたけど。
New/Scope Safe Constructors in OO JavaScript :: Mike Pack Development

まあでも、こんなエントリー書いといてなんだけど、多分自分は使わないと思う。一見、オブジェクトを生成しているようには見えないわけだし。

昔書いたif文中の条件文が見づらい


仕事で過去に書いていたソースコードをドキュメント化する必要が生じ、昔書いたソースコードを見なおしてドキュメント出力用のコメントを付け足していってるのだけど、いろいろとひどい。
いろいろひどい点はあるのだけれども、特にif文中の条件文がところどころ見づらい(醜い)。
例えば下記のような感じ。

変数名は異なるけど、こんな感じの書き方だった。とりあえず、なんとか何をしたいのか分かったものの、正直見づらい。ただ、今の自分でもどうやったらもっとうまく分かりやすくかけるかも思いつかないし、今でもこうしてしまう時があるので今でも過去の自分に怒る立場ではない。

例えば、先日、コードのネストを深くするな | anoparaというページを見たのだけれども、この中のisValidという関数、自分なら多分、下記のように書いてしまう。

今思ったけど、最初に書いたコードだけど、関数化すれば少しはマシになるかもしれない。例えば、下記のような感じで。

うーん。ちょっとだけマシになったような気もするけど・・・。まだ何かダメな気も・・・。こういう複雑な条件文の解決策って何かないもんだろうか・・・。

それ以前に、ここまで複雑な条件にする必要があるのかどうかをまず考えなおす必要があるのかもしれないですね。ただ、上記のeとかは仕様変更に伴い、後で増えた変数なんですが・・・。

JavaScriptのオブジェクトを定数として扱う方法


オブジェクト指向JavaScriptの原則という本で知ったのですが、ECMAScript 5からはオブジェクトをロックする機能があるようで、プロパティの追加や削除の禁止だけでなく、値の書き換えのようなこともできる方法があるようです。これで定数のようなことができそうだと思ってやってみました。Object.freezeというメソッドを使うとできるようです(参考:Object.freeze – JavaScript | MDN)。

確かに、Object.freezeメソッドを使うとオブジェクトの値が変更することができなくなりました。試しに、『Object.freeze(TAX);』の箇所を削除してみるとconsole.logの出力はそれぞれ『0.1』、『90』『2014』となりました。

ところで、定数というと思いつくのはむしろconst宣言だと思います(参考:const – JavaScript | MDN)。

ただし、const宣言にはIEは10以前では対応していなかったりそもそもECMAScriptで定義されていないなどいろいろ問題もあります(Object.freezeはIE9より対応)。さらにいうと、constで宣言したオブジェクト変数の値は変更できてしまいます。

ここまで書いて、ふと、そういえばさっきObject.freezeでプロパティ値の書き込みをできないようにしたサンプルではオブジェクト自体を変更してなかったなと思ってやってみた。

変更できてしまった・・・。

const宣言+Object.freeze()というのがある意味一番いいのかもしれません(そもそも、定数をオブジェクトとして扱う必要ってそんなにないような気もしますが・・・)。

2014年8月26日追記
このfreezeってオブジェクト内のメソッドからでも変更できないだろうかと思い、試してみた。

変更できませんでした(『Object.freeze(TAX);』の行をコメントアウトすると、0.1となる)。

オブジェクト指向JavaScriptの原則
オブジェクト指向JavaScriptの原則

jQueryをブラケット記法で書いている


二回続けてのブラケット記法エントリー。今回は普通、ドット記法で書くjQueryをブラケット記法で書いてみることに。

例えば、以下の様なHTMLがあるとします。

この時、idが”bracket-html”の中の要素のうち2つ目のoptionタグの要素内のHTMLを取得してconsole.logで出力する場合、ドット記法だと下記のように書くことがデキます。

いやいや、そこは『$(‘#bracket-test option:eq(1)’).html()』でいいだろ! と突っ込まれそうですが、とにかく上記のコードをブラケット記法で記述すると下記のようになります。

長ったらしいですし、括弧やシングルクォーテーションばっかりでわかりにくいです。普通はこんな書き方しないでしょうし、オススメもしません。ただ、ブラケット記法だとメソッド名に文字列の変数が利用できるので例えば、下記のようなことができます。

めったにこんな処理が必要なことがないとは思いますが、ブラケット記法だとこんなこともできるというサンプルです。

さて、ここで、いっそのこと『$』もブラケットに入れたい! と思う人がいるかもしれません。そもそもJavaScriptで作成したグローバル変数やグローバル関数はwindowオブジェクトに属しています。JavaScriptでは大抵windowを省略しますが、jQueryもwindowオブジェクトのメンバになっています。すなわち、『$===window.$』の結果はtrueです。というわけで、先ほどのブラケット記法での記述は下記のように書くこともデキます。

何々? どうせなら、『window』もブラケットに入れたい? そういう趣味をお持ちの人もいるかもしれません。windowオブジェクトにはtopというプロパティを持っており、これはウィンドウ階層における最上位のウィンドウへの参照を返します(参考:window.top – Web API インターフェイス | MDN)。よく分からない説明かもしれませんが、開いているページの参照を返すということです。すなわち、先ほどの記述は下記のように書くこともできます。

『top』もブラケットに入れたい場合は下記のような感じ。

『window』もブラケットn(ry。以下、無限ループ。