コンピュータやソフトウェアのあれこれ@道民(&元道民)
javascript
Head First JavaScript読書会 06に参加しました
5月 10th
5月7日(月)に開催されたHead First JavaScript読書会 06に参加しました。
GW明けの月曜日というハードな日程でしたが、無事、乗り切ることができました。
今回はFormのバリデーションと正規表現についてです。
Formのバリデーション
Formとは何ぞや?というところから、httpリクエストの話、httpメソッドの種類(GET, POST, PUT, DELETE, OPTIONなど)について一通りざくっとおさらいしました。
その後、Formデータの取得の仕方、バリデーションが大事な理由などについて話しました。
バリデーションの意義について、313ページには「本当に検討なアプリケーションになるとサーバー上でもデータ検証を行います」と書いてあるけれど、安全のためにはむしろサーバーサイドでデータ検証を行うべきだよなあという話をしました。
何度もサーバーとやり取りをするのもイライラするからちょっとした入力ミスを防ぐことができるよう、Javascriptの制御を入れておく、本当のデータチェックはサーバーサイドでやる、のが良い形なんじゃないだろうか。
安全のためのチェックはサーバー上で行い、クライアントサイドのバリデーションはユーザービリティ向上のために行う、というように目的を分けるという観点はとてもしっくりきました。
正規表現
本書では
- 必須チェックをしたい
- 桁数チェックもしたい
- 数字以外は入力してほしくない
- メールアドレスの形式じゃないものは受け付けたくない
というように、バリデーションのケースがだんだん複雑になってきたところで、正規表現が登場しました。
(よりによって、メールアドレスの正規表現を例に出さなくてもという話はちょっとでましたが)
Javascriptの正規表現は//で囲んで書きます。
"Hello World".match(/^\w{5}\s\w{5}$/)
---
[ 'Hello World', //マッチした
index: 0,
input: 'Hello World' ]
"Hello World".match(/^\w{7}\s\d{5}$/)
---
null // マッチしない場合はnullが返る
グルーピングは()で行うことができます
"Hello World".match(/^(\w{5})\s(\w{5})$/)
---
[ 'Hello World', // マッチした文字列
'Hello', // グループ1番目
'World', // グループ2番目
index: 0,
input: 'Hello World' ]
match関数ではなくRegExpオブジェクトを生成することもできます。
本書では自動的に生成されたRegExpオブジェクトを使う方法が載っていました。
var regex = /^\d{5}/
regex.test("12345")
正規表現はとても便利で、ある程度はできるようになっておきたいし、読めるようにしておきたい。
便利さを感じるようになってから読んだり書いたりを積極的にするようになった。
(正規表現使うたびにgoogleで量化子やメタ文字のリファレンスを探しているので、まだまだですが)
だけど、使いすぎると自分自身も後からメンテナンスが辛くなってくることがあるから、どこまで厳密にチェックするかも含めてさじ加減が大事かもしれないなぁ。
Head First JavaScript読書会 05に参加しました
4月 26th
4月23日(月)に開催されたHead First JavaScript読書会 05に参加しました。
04は旅の疲れからお休みし、1回あけての参加。
毎回進むページ数は多いのですが、本自体がとても読みやすいので、追いつくことができました。よかった。
今回は「関数」です。
Javascriptの関数は、知れば知るほど奥が深いのですが、この本ではその導入編を扱っています。
スクリプトから関数へ
ただのコード行を関数にしようとするとき、最初は結構つまづいたなあと思い出しました。
コードから関数を抽出できない、というのには色々段階があると思います。
- そもそも、何をする処理なのかわかっていない
- コードを理解していない
という、「もっとがんばりましょう」という段階。
- 重複や同じ処理をしている、というのが見えない
- 処理をかたまりに分けて考えることができない
という、「がんばりましょう」という段階。
読書会の時にも話をしたのですが、この段階の時に大事になるのは「IN/OUT」を意識することじゃないかな、と思います。
何かをもらって、何かを返す。
もらうもの、返すものの値が違っても種類が同じであれば同じ働きをしている -> 関数として抜き出すことができる! と形が見えやすくなってくると思います。
ここを乗り越えて感覚をつかめてきたら、その先の成長曲線は一気に上がるのではないかなー。
関数定義の方法いろいろ
次のコードはどちらも関数を定義しています。
<functionで定義>
hoge(); // ---(1)
function hoge() {
alert('hoge');
}
<変数に無名関数を代入>
huga(); // ---(2)
var huga = function(){
alert('hoge');
}
どちらも関数なのですが、定義されるタイミングが異なります。
なので(1)は実行できるけど、(2)はエラーになる(関数の巻き上げ)。
あと、無名関数として定義しておく(huga) と他の変数で参照できたりできる。
読書会で出てきたよい例示を忘れてしまいました・・・・ここ苦手。
コールバック関数
Ajax関連のコールバックは後半で出でくるのでここは主にwindowのイベント処理の話。
イベントハンドラを使うか、windowsオブジェクトのイベントに関数参照をさせるか、どっちをよく使うか、という話をしました。
<jsファイル>
var changeHoge = function{ alser('change!');}
window.getElemntById('huga').onclick = changeHoge
<htmlファイル>
<button id='huga' onclick='changeHoge()'>
これは、こっちであるべき、というよりは作っているプロダクトによって適した方があるのではないかなーと思いました。
あとはどのイベントか。onloadなどであればjsファイルに書いてあってもいいけど、onclickなどはhtmlソースから追えた方が便利かなと思いました。
こんな感じで初学者向けの本ですが突然深い話をしたりしています。
家で復習をする時に、読書会で出てきたサンプルコードを参照したいのでPCを持参しようと思うのですが、本が重すぎて実行に至っていません。
次回も楽しみです。
Head First JavaScript読書会 03に参加しました
3月 13th
3月12日(月)に開催された、Head First JavaScript読書会 03に参加しました。
本日は第4章「意思決定」。
if, switch
今回のメインはif、switchといった条件分岐。
条件分岐だけで1章使うのは贅沢…というか、薄く多くといった感じになりますね。
同じ事が繰り返されているので頭に入りやすいです。
javascriptの場合、やっぱりbreakをつけるのが大変&ミスしやすいので、ifを使う事が多いなあ。
「セミコロンはブログラム”文”の終わりにつける」
という考え方はなかったので新しい発見でした。
あと、本に書いていた「ifを繰り返すと効率が悪いからswitchを使う」というのはどの部分の「効率」なのか疑問が残りました。
【ifによる分岐】
var str = "E"
if( str == "A") {
alert("えー");
else if( str == "B" ){
alert("びー");
else if( str == "C" ){
alert("しー");
else if( str == "D" ){
alert("でぃー");
else if( str == "E" ){
alert("いー");
}
【同じ事をswitch文で書く】
var str = "E"
switch( str ) {
case "A":
alert("えー");
break;
case "B":
alert("びー");
break;
case "C":
alert("しー");
break;
case "D":
alert("でぃー");
break;
case "E":
alert("いー");
break;
}
これって、「評価回数」は同じだと思うのだけど、違うのだろうか。
評価回数が同じで、それぞれの評価コストが違う(caseでの評価の方がコストがかからない)、というのであれば納得できるのだけど「(ifの場合)5つのテスト条件が全て評価されるから効率が悪い」と書かれていた所に疑問が残りました。
<< 4/25 追記 >>
後日、この記事を教えてもらいました。納得。
ブラウザによってはswitch文がかなり最適化されているのですね。
現在はブラウザ(のjavascriptエンジン)がかなり高性能になっていてここまでの差はないという話もでました。
演算子、コメント、スコープ
途中で出てきた大事な事としては「各種演算子」「コメントの書き方」「スコープ(グローバル変数/ローカル変数)」の3つ。
コメントについて、コメントは「コードの動きを説明するために」書く必要があると書いてあったけど、どちらかというと「どうしてそう書いたか」を残した方がよいよね、という話をしました。(達人プログラマでもでできた話)
スコープについては「グローバル変数は本当に必要なとき以外は使わない」という方針が大事だなと思いました。
変数のスコープが大きいとどこで何をやっているかわからない不安があるから、スコープは可能な限り小さくしていきたいですね。大風呂敷を広げないというか、責任を持てるコードにするために。
今回の発見
「ゲームブック」という言葉を初めて聞きました。
「ゲームブックの14は死亡フラグ」というのも初めて聞きました。
あと、後輩の子がMacBookProを購入していました。(すごく)羨ましかったです。
Head First JavaScript読書会 02に参加しました
3月 1st
2月27日(月)に開催された、Head First JavaScript読書会 02に参加しました。
予習だいじ
今回は前日に該当範囲を読んでから参加することが出来ました。
やっぱり1回読んでおくことは大事ですね。
随所に散りばめられたユーモアをサクっと流しつつ、内容について話し合うことが出来ました。
どんなユーモアが飛び出してくるか、の耐性をつけておくという意味でも事前予習は大切ですね
今回の発見
今回の範囲は、Webアプリを作ったことがあれば、1度は触れることのあるトピックばかりでした。
びっくりしたのは、eval(関数評価)の考え方が突然出てきたところでしょうか。
eval
Timer.setTimeout("alert('hello!!')", 2000); // 2秒後に"hello!!"とアラートを表示する
この”alert(‘hello!!’)”がなぜ「文字列」なのか。
「文字列」じゃないとどうなるのか。
ブラウザのコンソール上で実験しながら詳しく説明してもらいました。
> var bbb = function(){alert('hogehoge')};
undefined
> bbb
function (){alert('hogehoge')} // 文字列がでる
> bbb()
undefined // 実際にアラートが表示される
メモ:nodeを使ってプロンプト上で確認するときはConsole.logを使う
cookie
Cookie周りのソースは、複雑であることを加味してもサンプルソースがちょっとよくないなと思いました。
もう少し見やすくするためには ‘;’ という区切り文字列を、変数に割り当てるか、
‘;’ で結合するためのfunctionを作るか、もう少し可視性の高いコードにしたほうが良いと思いました。
実際に書いてみたら難しいのだけど。
【before】
var date = new Date(); date.setTime(date.getTime() + (30 * 24 * 60 * 60 * 1000) ); var expires = "; expires=" + date.toGMTString(); document.cookie = name + "=" + value + expires + "; path=/" ;
【after(冗長かも)】
var data = keyValue(name, value);
var date = new Date();
date.setTime(date.getTime() + (30 * 24 * 60 * 60 * 1000) );
var expires = keyValue("expires", date.toGMTString());
var path = keyValue("path", "/");
document.cookie = createCookie([data, expires, path]);
function keyValue(key, value){
return key + "=" + value;
}
function createCookie( params ) {
var val = "";
for(var i = 0; i < params.length; i++ ){
if(i != 0 ) val += ";";
val += params[i];
}
return val;
}
※ 書いていて、”=”もうっとうしい事に気がついた
まあ、ライブラリを使うのが確実だと思います。
次回も予習してちゃんとのぞみたいと思います。
4月に入ったらセクションのナビゲーターを担当したいなと思います。(決意)
Ruby Sapporo Night vol.14 に行ってきました
2月 25th
2月23日(木)に開催されたRuby Sapporo Night vol. 14 『Ruby札幌 × Sapporo.js』に行ってきました。
このイベントはRuby札幌がApple Store Sapporoで行っているイベントです。
Ruby札幌の方達の今やっている、気になっている技術のお話を聞けたり、他コミュニティとのコラボ企画で色々な分野のお話を聞く事ができます。
不定期開催、事前登録不要のイベントです。
開催はRuby札幌のサイトやAppleStoreのイベントカレンダーで知る事ができます。
リッチクライアントを中心とするセッションのリンク
前半は、Ruby札幌の島田さんによるセッション
「リッチクライアント時代のWebアプリケーションアーキテクチャパターンについて考える」
”MVC” をキーワードに、従来のMVCとは、そして現代のリッチクライアントに必要なMVCモデルの形についてとお話が発展していきました。
後半はSapporo.jsの佐藤竜之介さんのお話
「Testable JavaScript」
”テストしやすいJavascript” にするためにどのように設計をし、コードを書いていくのが良いか。
Testableにしていくために、MVCモデル(KATA)を考えていく事が大事になると言う話でした。
参加していてとても面白いなあと思った事は、全く違うアプローチから入っていっている両者のお話が、絶妙にリンクしていってたんですよね。
核となる部分に同じ思想があって、それにそれぞれの形で向かっている。
うまく言えないのだけど、すごく気持ちのよいイベントの流れがありました。
あと、お二人のスライドはどちらもお二人の話以外のたくさんの情報が詰まっている。
とってもためになる資料です。公開されている事に感謝です。
リッチクライアントのためのMVC
ちょうど数ヶ月前に「Javascriptのテスト、すごく難しい」と思う事があり、どういう形でテストしていくのがいいのかなーと考えていたので、りゅうのすけ氏のアプローチはとても興味深かったです。
テストツールやテスト用のライブラリの紹介も最後にあったのですが、それよりも「KATA」。
手を加える度に、進歩して行ける開発を!
デスクトップアプリケーションを作った時に学んだ考えも生かしつつ、「良い設計」について考える機会・・・もとい
「良い設計」を意識する気持ちを持つ事ができました。
Javascriptだから、時間ないから無理、と諦めないこと大事。
良い時間を過ごす事ができました。ありがとうございました!
Head First JavaScript読書会 01に参加しました
2月 14th
2月13日に行われたHead First JavaScript読書会 01に参加しました。
この読書会は、Head First JavaScriptの決まった章を読んできて、追加説明を交えながらJavasciptを基礎から学んでいく勉強会です。
しょっぱなから今日の範囲(1章と2章)、流し読みで参加してしまいまして・・・苦労しました。
次回からはちゃんと読んでいきます。
知らなかった事いろいろ
へえ!そうなんだ!と思った事色々を箇条書きにしておきます。
外部ファイルとして定義したスクリプトファイルのキャッシュを適切に制御する
<script type="text/javascript" src="hogehoge.js?20120102"></script>
ファイル名の後ろに任意の文字列をつける事ができる。
内容を変更したタイミングで末尾の文字列を変えると別ファイルとして認識されるのでキャッシュクリアされる。
あと、scriptタグは外部ファイル定義するときも /> で閉じてはいけない。
prompt
使った事なかった・・・。
constで定数定義、遅延初期化はできない
const A; A = 10; alert(A); // undefined
こんな形で使う事ないけど、しらなかった。
constで定義した定数のスコープってどうなるんだろ。
+演算子のルール
前から評価、前から型を推測。
1 + 2 => 3 "1" + "2" => 12 1 + "2" => 12 1 + 2 + "4" => 34 "1" + 2 + 4 => 124 true + 3 => 4 false + 3 => 3 true + true + "3" => 23 true + "3" => "true3"
parseIntとisNaN
isNaNの方が数値の定義が厳しい。
isNaN("200aaa")
=> true
parseInt("200aaa")
=> 200
parseIntとN進数
0が先頭だと8進数、0xが先頭だと16進数に勝手に解釈される。
文字列から適切な進数に変換するためには第二引数を指定する。
parseInt("077")
=> 63
parseInt("077", 10)
=> 77
ルート、ノード、リーフ、エレメント
(この辺はもう頭が沸騰していてアレでした)
親がルート、末端がリーフ、それぞれがノード≒エレメント。
エレメントのidは重複しちゃだめ、絶対。
今日の発見、ここまで。
—–
学ぶ形式の勉強会、仕事終わりだとなかなかハードですね。
アジャイルサムライ読書会や達人プログラマ読書会とは違った部分の脳を使います。
終わり30分前くらいにはぐったりしていました(電池切れ)。
体力つけないと、と感じた勉強会でもありました。
次回、リベンジできるかな。
Sapporo.js-2012.01.28に参加しました
1月 30th
1月28日(土)にSapporo.jsの勉強会、Sapporo.js-2012.01.28に参加してきました。
だいぶ間が空いた久しぶりの参加です。
読み合わせをする本、JavaScript: The Good Partsを購入して臨みました。
配列
6.7 次元から。
配列の初期化について、多次元配列の初期化の注意、単位行列を生成するメソッド。
単位行列・・・については、そもそもそれが何か良くわからなかったのでその場でぐぐりました。
オブジェクトが参照されるので代入時に注意する事、Objectをコピーする場合はJSONコピーを使う事。
JSONコピーの方法は知らなかった。
JSONコピーはプロトタイプはコピーしないのを確認したコード。
var hoge = {a:1};
hoge.__proto__ = {c:3}
console.log(hoge); // {a:1}
console.log(hoge['c']); // 3
var hoge_json = JSON.stringify(hoge);
console.log(hoge_json); // {"a":1}
var foo = JSON.parse(hoge_json);
hoge['b'] = 2;
console.log('hoge', hoge, hoge['c']); // hoge {b: 2, a: 1} 3
console.log('foo' , foo, foo['c']); // foo {a: 1} undefined
for-inの話も面白かった。ちょうど業務で「each使いたいけど使えない、その結果なんかすごいコードがかっこわるい」状態になっているのがあって。(結局for-inはあまり使わない方がいいという話になったのだけど)
あのかっこわるいコードどうしようかな・・・。
(jQueryを入れるほどの画面でもないテスト画面のコードなのだけど気になる)
正規表現
魔術みたいな正規表現
var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
を読み砕いていきました。
部分ごとに分けて考えると、なるほどーとなっていくところが、勉強会の楽しいところだなあ。
最初の
(?:([A-Za-z]+):)
が一瞬顔文字に見えていた私、一人だったらページを流し読みして終わりそう。
上記はURLを判定する正規表現の例です。
たぶんすべての()内に文字が入るとこういうURLになる、はず。[]はキャプチャグループで区切ってみた。
[[http]:][//][terakonya.sarm.net][:[8080]][/getList][?huge][#top]
node.jsをインストールした
マシンに入れずじまいだったnode.jsを、写経中にインストールしました。
といっても、
$ sudo brew install node.js
v0.6.9がさくっとインストールされました。
りゅうのすけ君がスクリーン上でnode.jsを使いながらサンプルをタイピングしてくれていたので、見よう見まねで実践する事ができました。また少しjsと近くなれた気がします。
今回は会社の同僚も勉強会に参加していました。
一緒に仕事をしている人に勉強会で会うと、嬉しいですね ![]()
またよろしくお願いしますー!
Lionを入れたらnpmがダメなコトになった
11月 9th
別にダメじゃなくて、Lionを入れたコトによってダメになったっていうお話。(*1)
他の方はどうなんだろう。
例えば、
$ npm list
で、過去に入れたモジュールが出て来ないとか。(*2)
そんでもって、
$ npm update npm -g
って入れたら、エラーが出て npm が消えました。
おしまい。
じゃなくて、古いメモを見ながらnpmを入れ直してみました。
$ npm --version
も、ちゃんと動いたし、
$ npm search coffee-script
も、すんごい時間掛かって検索してるみたいです。(初回は時間が掛かるみたい)
で、ちゃんと見つかったかというと・・・。
すんげー時間掛かってる。
って思ったら、ターミナルがスクロールされなくて、終わったのに気付かず・・・。
という訳で、めでたし、めでたし。
(*1) npmのバージョンが古すぎた説は拭えてない。
(*2) 勘違いしてたのですが、-gオプション付きでインスロールした場合、
$ npm list -g
で、インストールしたモジュール一覧表示なんですね。
(だとしたら、手動で古いモジュールを削除しなければ良かった。)
Web Audio APIはじめました
10月 25th
(function () {
var ctx = new webkitAudioContext();
//console.log( ctx );
var dst = ctx.destination;
//console.log( dst );
var buf = ctx.createBuffer( 1, 4096 * 4, ctx.sampleRate );
var data = buf.getChannelData( 0 );
for (var i=0; i<data.length; i++) {
data[i] = ( i % Math.floor(44100 / 440) );
}
console.log( data );
var src = ctx.createBufferSource();
//console.log( src );
src.buffer = buf;
src.connect( dst );
src.noteOn( 0 );
})();
なんか分かんないけど、こんな感じのコードで音が鳴った。
Canvasのように、まずcontextを取得するのは分かる。
W3CのAPIリファレンスを見ると、contextでいろいろ生成するみたい。
よく分かんないのでconsole.log()を使って、
何が入ってるのかChromeで確認しながら作業した。
(こういうとき英語読めたらいいなーって思う。)
とりあえず、エラーが出ないように、見よう見まねでコードを書いて、
きっと波形を入れればと思って、それっぽく初期化したら音が出た。
あと、Chromeでテストしてるけど、Chromeごと落ちることがあるらしく、
自分も1回落ちたけど、再現性はない。
下手なコードを書いたからとかじゃないらしい。
早くループさせたりフィルターをいじってみたいけど、
perlも待ってるのでバランス良くやる方向で。
おしまい。
10/26 追記
MacBookAirでスリープ解除してから
このスクリプト実行したらChromeごと落ちて、
そのあとは普通に音が鳴ったので、
このスクリプトは良くないのかも知れないです。
IEでAjaxGETリクエストを送ったときにキャッシュされたレスポンスを返してくる件
10月 15th
今回、この状況に直面して初めて知ったのでメモ。
ブラウザ上でAjaxを使用した通信を行う(ブラウザからサーバーへgetリクエストを送る)際に発生しました。
Ajaxで送るgetリクエスト
$.get( "/addpoint" ,
{
"id" : id ,
"pt" : point
},
function(result){callback(result);}
);
このとき生成されるURLは http://hogehoge/addpoint?id=xxx&point=yyy になります。
IEで起こったここと
xxxとyyyの値が以前と同じだった場合(同じURLになる場合)キャッシュしてあるレスポンスを返してくる。
つまり、
IE( °⊿°) < 「URLが同じなんだから結果も同じだよね。」
と判断して、サーバーに聞きにいかずに最初の結果を返し続けるわけです。
(上記で言うと変数resultが常に同じ値-最初にリクエストした時の結果)
ちなみに他のブラウザではこのような処理は行われていないよう。
困ること
確かに無駄な通信は減りますが、URLが同じでもサーバーから違う結果が帰ってくることを期待している場合困ったことになります。
(今回の場合は、サーバー側でパラメーター値分の加算/減算が行われることを想定)
サーバーが異なる結果を用意していても、リクエストが送られないので問い合わせられないわけです。
いやあ、まさか、そんなことがあるなんて思いもよりませんでした。
対策
以下のような対策があるようです。
- POST送信しましょう
- リクエスト毎に変動する値をパラメーターに追加しましょう(サーバー側では捨てられる)
- getリクエストのHTTPヘッダに「If-Modified-Since」を設定しましょう
現在は、「リクエスト毎に変動する値をパラメーターに追加」しています。
パラメーターとしては「1970年1月1日午前0時からのミリ秒」を与えています。
$.get( "/addpoint" ,
{
"id" : id ,
"pt" : point,
"tm" : new Date().getTime() //捨てられる
},
function(result){callback(result);}
);
これでIEでも毎回サーバーにリクエスト送信するようになりました。
改良
無駄な通信が発生しているのでリクエストのHTTPヘッダに「If-Modified-Since」を設定するのがいいのかもしれない。そもそもPOSTにするのがいいのかな。
– 追記
以下のようにIf-Modified-Sinceを設定するようにしました。
$.ajax({
beforeSend : function( req ){
req.setRequestHeader("If-Modified-Since", "Thu, 01 Jun 1970 00:00:00 GMT");
},
cache : true,
type:'GET',
url:'/addpoint',
dataType:'json',
data:{
"id" : id ,
"pt" : point
},
success: function(result) {
callback(result);
}
});
JQueryで用意されている簡易版メソッド$.getではなく、$.ajaxを使うことでリクエストのHTTPヘッダに値を設定できました。
教えてもらったこと
WindowsPhoneアプリケーション開発をする際にも同様のことが発生しているようです。