さて、前回のエントリの続き。
再掲しますが、LingrのログとUstの録画映像はこちら。
それとECMAの構文定義
※Ustの録画が全て整理されて公開されたので、一部リンク等を修正しました。(1/19)
Kanasanさんの書いた図の通りに机が再配置sれ、2時前後から読書会スタート。
○読書会を始める前に
ブラウザ上でJSのコンソール実行環境を作ってくれるブックマークレット『Jash』の紹介。
及び、Jashの実行結果をキャプチャーしてLingr(やTwitter)にpostしてくれる『Jashture』の紹介。
メモ:止める時は『jashture.stop();』
読書会の進め方等の説明。
全員で指定範囲を読み、疑問点等は全員に聞こえるように発言、答える側も全員に聞こえるように。
多言語との比較はかまわないが、他言語中心の話題は極力避ける。
隠語等は使わない(PではじまりPで終わる、間がHな3文字の言語 とか)。
開始前にcuzic先生の著書の紹介。
Rubyist Magazine出張版 Ruby on Windows
81~103ページ 読書スタート。
1/14 : 2:14pm cuzic : みんな本を読みながら黙々とチャットする
1/14 : 2:16pm ujihisa : というかみんな喋れよ
○switch-case case ラベルに任意の expression が書ける事について
kanasan : switch(true)しておいて、case に真偽値をとる条件式を書いたりできて非常に便利
「case は==ではなく===を使って比較されます。」
関数呼び出しも式なので、caseラベルに指定可能なんすよね。
○caseの判定順序
上から順に判定される。
よってcase内の式も上から順に実行される。
またcaseは判定がtrueになった時点で以後の実行は行われない。
breakが挟まれなければ、次のcaseラベル内の文も実行されるが、そのさいにcaseラベルが評価される事は無い。
function t1(){console.debug('t1');return 1;}
function t2(){console.debug('t2');return 2;}
function t3(){console.debug('t3');return 1;}switch(2) {
case t1(): console.debug('test1');break;
case t2(): console.debug('test2');
case t3(): console.debug('test3');break;
}
↓実行結果
t1
t2
test2
test3
○式と文の違い
P59「JavaScriptインタプリタが評価して値を生成できるものを式と呼びます。」
P81「通常式そのものは何もしません。JavaScriptに何かをさせるものが文です。」
『i=0』は式だが、『i=0;』は文らしい。
emaさんと話してて納得できた結論は「if文の中に書けるのが式」という事だった。
評価可能であるか否かという所か。
○関数が式の場合と文の場合
関数が式になるか文になるかは文脈によって異なる。
文の終わりの次にfunctionが来れば、それは関数宣言になるが、
『(』の後にfunctionがあれば、『(』の後には式しか置けないので、無名であるか否かに関わらず関数式になるという話し。
関数式を評価すると関数が返るが、関数宣言を評価するとundefineが返る。
(こっからサッパリだったので俺のまとめもおかしいかも。
文が終わって無名の関数が始まった場合はECMAの構文上はエラー
FireFoxのJavaScriptでは関数宣言として扱われる
function(){alert(2);};と単体で書いてもエラーが発生しない。(でも呼び出せないよね?
function a(){alert(2);}();alertが実行される。
x = function a(){alert(2);}();Syntax Error
function(x,y){alert( x+y);}(5,10);
alertは返らないがエラーも発生しない。
評価結果というかFireBufやJash上では『10』が返る。
この場合の後ろの『()』は関数呼び出しの演算子としての『()』ではなく、PrimaryExpressionの『()』として解釈される。
○PrimaryExpressionって何?
amachang : this, literal, (literal), identifier = primary expression
ってか何でECMAの内部的な話しにノ|'◇'|ヽ
yhara : リテラルと、カッコでくくったもの +識別子(変数参照とか)
構文木の端っこにあるヤツ
○for/inの気持ち悪い使い方
P91の一番下
for(a[i++] in o) ;
とすることで、oの全プロパティを配列としてaに移せる。
この発想は無かった。
そしてあまり使って欲しくない。
○サイ本のラベルの掲載位置
6.10 ラベルより先に、6.11 break/ 6.12continueを読んだほうが良いらしい。
ネストしないループにおけるbreak,continueを紹介したあとに、多重のループからの脱出の話しでラベルと一緒にbreak,continue紹介すりゃいいのになーって感じかな。
○ループ以外にラベルを付ける意味
continueはwhile,do/while,fo,for/inの4種のループでしか使えないが、breakはループである必要は無い。
この辺に関してはnanto_vi先生がご自身のブログに例を挙げて書かれている。
userChrome.js 用スクリプト: Days on the Moon
○breakの戻り先を分岐させたりはできるのか?
結論から言うと不可能。
breakの後ろにはlabelしか置けない。
break (true ? main1 : main2);とかはinvalid breakが返る。
○eval内のbreak
eval内でbreak指定できるのは、eval内のlabelのみ。
test:{eval("break test");
console.debug(2);
}
console.debug(1);
これは『label not found』となる。
○function文による関数定義は実行されるのではなく解析されるのだという話し
P97のサンプルソースの通り、function文が解析されるのは実行時ではなくJavaScriptパーサーがソースを読み込んだ段階。
○if文等により関数宣言を分岐させることは出来ないのか。
ECMAの仕様上、関数宣言はグローバルであれ、関数内であれ、その内部のトップレベルにかかれて居なければならない。
そのため、ifの分岐の中に書くことはできない。(→Syntax Error
ただし実装はそうなっておらず、実装に依存した動作をする。
if(true){
function x(){alert(1);};
}else{
function x(){alert(2);};
}x();
ECMAScriptの場合→SyntaxErrorになる。
JScript(IE)の場合→2のalertが表示される
JavaScript(FireFox)の場合→1のalertが表示される
さて、このifの評価内容をfalseに変えた場合どうなるか。
JScriptの場合→2のalertが表示される
JavaScriptの場合→2のalertが表示される(!!!
FireFoxではifでの分岐が行えている!
実装に依存するので、この記述方法は使わない方がいいですね。
並列記載時にIEではかならず後者、FireFoxでは正常に動作するなら。
if(true){
function x(){alert("JavaScript");};
}else{
function x(){alert("JScript");};
}x();
とかできますねヽ|'◇'|ノ (あほか
なお関数の生成を分岐させたい場合は、無名関数を変数に代入する形で関数を生成すれば、意図した動作を行わすことが出来る。
○同名の関数を並列に宣言した場合は?
この場合はIE、FireFoxに限らず全て後述された関数宣言の方が有線された。
○空文の使い方の話し
サイ本上ではコメントを記載すると書かれているが、kanasanはブロックを書いた方がわかりやすいとのこと。
if(...){;}
俺は改行入れてインデントずらして入れる形で考えてます。
if (tyoro)
;
○空文に関する記述で「注意してください」って書いてるけど、注意できないから問題が・・・
実際に注意できなくて問題が発生する場合はある。
これを防ぐ事が出来なくても、こーゆーミスが発生することを覚えておくことはデバッグ時に役立つ。
キーボードの「;」に「;+Enter」を割り当ててる人が居るらしいwww
もし「;」を単体で打ちたい場合は「;+Enter」が記述された跡にBackSpaceで戻る。
「;+Enter」の方が記述頻度が多いので、typing数が大幅に削減されるとかwww
○varはなんで文なんだろう?
amachangからの質問。
varは「SymbolTableにSymbolを追加する」式でも問題無いんじゃないか?
戻り値はundefineでかまわない。(代入されている場合はその値を返すのかな。
varが式であれば、『while(var x = ....)』という記述が可能になる。
perlだとvarは関数。
○for文のinitialize部にはvarだけを許可してるのか、それとも他の文が書けるのか?
『for(a;b;c) のaの部分』
varが文であるなら、initialize部には他の文も書けるかという話しがあった。
書けるならforのinitialize部にforを書くとかできんのかな?
結論は無理。
サイ本にはinitialize式と記述されており、通常
代入などの副作用を伴ういます。...varを使って変数を宣言することも出来ます。
とあるのですが、実際にECMAの仕様はどうなっているかというと。
for (ExpressionNoIn[opt]; Expression[opt] ; Expression[opt] ) Statement
for ( var VariableDeclarationListNoIn; Expression[opt] ; Expression[opt] ) Statement
for ( LeftHandSideExpression in Expression ) Statement
for ( var VariableDeclarationNoIn in Expression ) Statement
とあり、ExpressionNoInかVariableDeclarationListNoInが書けるとある。
つまりvar宣言かExpression(式)しかかけないとのこと。
○ExpressionNoInのNoInってなんだろう??
一般的名ExpressionではなくNoInって書いてるのは何だろうと思ったら、forの中にinが含まれるとfor/inと解釈されるためにinを例外とするExpressionって意味っぽいwww
ちょwwwどんだけ例外だよwww
(あくまで説だけどw
さて、6章を終えて休憩を挟み7章『オブジェクトと配列』 p.105~p.122のスタート
○ 「.」って「演算子」なのか?(amachang)
日本語版のECMAScriptの仕様書には演算子と書かれているが、英語版では違う表現をが使われている。
英語では「accessor」。
ema : 11.2.1 プロパティアクセス演算子 (Property Accessors)
ema説:「.」は「[]」の別名なので、「演算子」というより「シンタックスシュガー」なのではないか
シンタックスシュガーとは: 文法上、他の書き方ができるが、簡便のために用意されている構文のこと。
yuyakato : でも、identifierとidentifier-stringは別では・・・
[]だと数字も指定できるが、.の後ろだと数字から始まるものは識別子になれないので指定できない。
つまりシンタックスシュガーとはいえないのではないか。
akipii : kanasan.jsはEcmaScriptの仕様書を読む読書会になりました\(^o^)/
○『.(ドット)』によるアクセスと[]によるアクセスはどちらの方が早いのか?
.の方が早そうだが、[]内が単純な文字列の場合はspidermonkeyから全く同じ中間コードが吐かれた。
つまり同じ。
[""]と.だとtyping速度に大きな差が!というお話とか。
確かに"だとShit+2で入力負荷が高いがUS配列のキーボードなら'を打つことでコストが下がります!
kanasan : キーストロークも禁止ワードになっちゃうよ
○ undefinedの周辺
var undefs = [,,];
var undefs = [undefined, undefined, undefined]
だと下の場合はundefs[0]が存在するが、上の場合は存在しない。
しかも前者だとlengthは2、後者だと3になった。@FireBug
undefined = void(0)
nullは予約語だが、undefinedは予約語ではない(単なるグローバル変数)
(この辺の話しは前回の読書会でもされてましたね(僕は遅刻したので聞いてませんが
○prototypeチェーンの話しとかJSのプロトタイプベースの話し
とかされてたんだけど、ちょっとついていけなかったの録画映像が無いのでまとめられそうにない。
断片だけでも気になる人はログ読むといいよ!
ってかprototypeは9章のはn(ry
ホワイトボードを使って、amachangの考えるプロトタイプベースの世界の話しとかもあったり。
A=function(){}
A.prototype = {
get: function() {return this.x*2;}
}
a=new A();
alert(a.constructor==A);A=function(){}
/*A.prototype = {
get: function() {return this.x*2;}
}*/
a=new A();
alert(a.constructor==A);
1回目のalertはfalseだけど2回目はtrue。
1回目はprototype.constructorが書き換えられている。
マージしなきゃだめらしい。
○プロパティと配列の添え字
「0」というプロパティをオブジェクトに追加したとすると、配列の添字としては「0」は使えない、んですか?
配列の添え字としてa[0]と書かれているのは、内部的にはa['0']と同様である。
そのためa['0']を上書きすれば、a[0]も書き換えられる。
a = new Array();
a[0] = "test";
a.push(4);
a[1];
上記のようにa[0]に値をセットした後にpushによる値を追加した場合、新しい値は添え字[1]に設定されている。
a = new Array();
a[1] = "test";
a.push(4,7);
a[2];
のように記述した場合、a[2]の評価結果は4になる。
pushは使用されている添え字の最大値の次の値を追加する値の添え字に使用するらしい。
この辺で時間切れになったので、終わりーヽ|'◇'|ノ
今回はP112 7.4.7まで進めたので、次回は『7.5 配列』からスタートします。
○なお今回読書中に設定された禁止ワード一覧
・式と文
・JavaScript
・nitoyon
ujihisa : 禁止ワード: nitoyon
nitoyon : ちょw 発言できない
それにしても、以前oqunoの家で鍋食ってた時に、nanto_viさんとnitoyonさんが居られる中でまったくプログラムの話ししなかったのは、激烈勿体無かったんじゃないかと思えてきたわ( ´-`)
今回もすげー楽しかった。
そして勉強になった。
まとめることも勉強になった。
次も参加したい。
(そのためにも早めに日程を決定してほしかったり・・・
懇親会行けなかったのが心残りだけど、もうサイフに1500円も無かったんです( ´-`)
情けなや( ´-`)
最後に、すでに何人かの方が今回の読書会についてblogに書かれているようで、それをまとめられている所を紹介。
Kanasan.JS JavaScript第5版読書会#2 参加者のブログ記事一覧
higeorange’s bookmarks tagged with "js:reading+#2" on del.icio.us
お疲れ様でした!
function式を直接呼び出すときは、function式全体を括弧でくくるといけますよ。
(function a(){alert(2);})();
ほんとだ!
でもこれって、a()で関数本体を呼べないみたいなので、()で囲む事によって、関数宣言ではなく無名関数を生成する関数式に変化してるみたいですね。
ちょっとコレに関して1エントリ書いてみますね。
ustが何らかの原因で中断すると、録画していた映像は非公開状態で保存されるようです。
ユーザ操作による停止ではそのときに名称を決めて公開状態で保存できるのでそのままでも見れます。
この辺りを整理し、名称を変更したり公開にしたりしました。
今ならほとんど全部視聴できるはずです。
prototypeとconstructorについては、以前のKanasan.JSのプレゼンでやったので、見てみると参考になるかも。
http://www.kanasansoft.com/weblab/2007/11/kanasanjs_2.html
追加修正いたしました!
prototypeとconstructorについて、勉強させていただきます><