SSブログ

JavaScriptのオブジェクト指向ってのは、連想配列が起源か。 [プログラミング]

プロになるためのJavaScript入門、の中身の続き。ダラダラ読みながらツッコミを入れていく感じで。

引き続き、基礎的な文法ですが、他のオブジェクト指向プログラミングを念頭に置くとハマる部分があるね。JITコンパイラで動作時にコンパイルされているようですが、動的言語というか実行時に解釈される事が多いのが、コンパイル型の静的言語とは挙動がかなり違う。

今日はまたJavaScriptの文法。でも、かなり深いところまで行く。中級とか言っておきながら、コードのパーシングまで言及しているので、かなり細かいところまでやってる。ぐだぐだ行きます。これだけ読んでもきちっと覚えられるような文章にならないと思うので、この本か別のきちんとEcmaScriptの文法を説明した本で理解してください。

プロになるためのJavaScript入門 ~node.js、Backbone.js、HTML5、jQuery-Mobile (Software Design plus)

プロになるためのJavaScript入門 ~node.js、Backbone.js、HTML5、jQuery-Mobile (Software Design plus)

  • 作者: 河村 嘉之
  • 出版社/メーカー: 技術評論社
  • 発売日: 2012/12/07
  • メディア: 大型本



 
元々、JavaScriptはオブジェクト指向を目指して作ったものではないと思うのだが、いつの間にかにオブジェクト指向言語になっていた。正直、細かい紆余曲折は知らないのだが、ECMAScriptに準拠した所が一番の転機だったのではなかろうかと想像する。

雑誌で、JavaScriptでは「連想配列=オブジェクト」である、ということに違和感を覚えた。確かにメンバーが連想配列のキーバリューになっているが既存のものを使うのかと考えると、ただ今までの文法を崩さないようにしているだけに見えてしまう。でも、C++のオブジェクト指向を考えて、恐らく構造体の拡張がクラスだと考えると、同じようなものだと思えてきた。構造体の中身のデータが、変数と関数のポインタとかに置き換えれば、あとはカプセル化とかアクセスの制御などを考えれば大した違いはない。まぁ継承とかもっと大事な部分があるけど、おおまかな枠組みとしてのオブジェクトとして、ですね。

そういう意味では、連想配列のそのものの構造をオブジェクトとして使うのは、特に際立った特徴ではない。関数のFunctionもオブジェクトだし、配列も(プリミティブ型じゃないラッパーオブジェクトの方は)Arrayオブジェクトだ。プリミティブ型の数値なども、ラッパーオブジェクト(プリミティブ型と同じ型のオブジェクト)のメソッドとか使えるので、結局、全部オブジェクト指向の息がかかっていると言える。やっぱり、プリミティブ型を丸カッコでくくって、ドットでメソッドを使うとか、そもそもプリミティブ型が要らないんじゃないかと思うんだが。でも、===とかでプリミティブ型とオブジェクト型で比べたら、falseになるんだよね?

Rubyみたいに数字も何もかもがオブジェクトとされたほうが飲み込みやすい。確かに動作的にオブジェクトじゃなくて、プリミティブなデータのほうが動作も速いし、メモリも食わない(初期のJavaもそうだったし)。でも、プリミティブ型にメソッドをJavaのオートボクシングみたいに使うなら、はじめからオブジェクト型でやっちゃったほうが一貫性がある気がするんだけどなぁ。まぁそこのところはJITで矯正されちゃう気がするんだけどね。厳密性を求めるために、フランクな書き方で説得力がなくってるような…。

オートボクシングとか、Javaに特有の言葉じゃない? いきなり真剣に使ってない言語のテクニカルターム使われても分からないんですけど…。逆がアンボクシングですか。ボクシングってのは、プリミティブ型からラッパーオブジェクトに変換することかな? これ以上あんまり突っ込みたくない。


クロージャっていうものの性質が、いまいちよくわからないな。

あと無名関数を使ってるからか、hoge()()みたいな書き方もできるんだよね。ここもなんつーか、気持ち悪い。

オブジェクトで自分自身を指すthisは、実行時に参照先が確定するので、実行するまで変えられない。Functionクラスのcall()かapply()かbind()で明示的に指定できるらしい。あ~apply()の使用例が載ってないな。そういうところは、網羅的なリファレンス目的の本ではない。


変数のスコープも元々関数とグローバルしかなくて、C言語系のif文のブロックのスコープとかがなくて、関数のブロック以外は全部グローバルの状態だったらしい。なかなかひどいな。しかも、同じ変数を重複しても後出しジャンケン的に後から書いたほうで上書かれる。エラーなどにならないからバグの素だ。

レキシカル環境とか、スコープチェーンという名前とかがありますが、スコープチェーンについての言及がなぜかない。結局のところ、関数内も入れ子にした関数の中では、普通に関数のブロックで区切られた通りにスコープが働くようになったらしい。スコープを意識して書くには、無理くり関数で区切らないといけないみたいだ。これもJavaScriptで特別な事情だから認識していたほうがいい。{}というブロックに囲まれていても、関数以外はスコープの仕切りが存在しないので、C言語系の直感から行くとかなりバグの元になりやすいだろう。



上級編と称していろいろあるけど、人のソース読むには必須でしょ。EcmaScriptの仕様から読めるようにしましょうとか書いてあるんだけど、それって説明放棄かよって思ったけど、まだまだ最新の仕様は詰めの状態になっていないらしく、正確な実装はそこから読み取るしかなさそうです。面倒くさいなぁ。そこまで細かくやるつもりはないんだけどなぁ。

JavaScriptにもカプセル化みたいなものがあって、それらはプロパティ記述子といわれるもので実現できるみたい。とはいえ、JavaScript自体がプロトタイプオブジェクト指向なので、インスタンスを拡張する事になるんでしょうから、きっちり設計したクラスで継承っていうような仕組みにはなっていないんですよね、たぶん。というか文法のキモになってきそうな継承とかの話って、基本の文法のところでやらないのね。随分先の第七章の「大規模開発」ってことろでやっと継承の話が出てくる。網羅的な文法って意味では、そっちを先に読んだほうがいいのかもしれない。あ~そっちで継承とかの話でカプセル化使えるね。構築するところと、実際に使う所でのアクセス制御をしているってことなのかな。これも面倒だなぁ。

第二章の上級編とやらを続けるとして、プロパティ記述子というものがあって、範囲内で変更を凍結させることができるらしい。というか、それまで変更を禁止することが出来なかったって、オブジェクト指向言語としてどうなのよ。ざっくり指定するのは、

preventExtensions()
seal()
freeze()

があるらしい。
プロパティ記述子そのものとしては、

Enumerable for-inで無視するかどうか
Configurable プロパティ記述子の変更を禁止するかどうか
Writable Valueの変更の禁止うんぬん
Value 見たままキーの値


って随分一つのデータに関して細かい制御をするもんですね。そこいらへんの制御は上の3つでザックリ指定するか、細かいプロパティをいじるかどうかになっているようです。あと大抵いつでもいじれる

defineProperty()
getOwnPropertyDescriptor()

とかがある。イマイチ使い方のセオリーがわからないまま進む。多分、そこいらはきちんと書いてあるんだか微妙な気がした。まぁどのくらいまで書いてあるかは買って読んでいただくと詳しくわかると思います。正直わかりづらい。


型変換は独特で、+を変数の前に付けるだけでNumber(hoge); みたいな変換を+hogeで示せたりする。何じゃそりゃ。流れ的に計算する演算子で数値に変換されるとかならわかるけど、数字へのキャストが+付けるだけってのもすごいね。ということは、実用性のないコードだけど、

var hoge = "1";
var num = +hoge;

とかでもいいわけなんだろうか。C言語にある+=演算子があったりして間違えたりしないよね。

後は~~とか、!!とかがあるので、注意しとく。とりあえずテクニカルに書きたい人はそういうのを多用する癖があるので、書かなくても読めるようになっている必要はある。C言語ではわざと読みにくくしてるんじゃないかというソースがあったので、そういうのを読み込むのは慣れてはいるけど、そういうのが嫌いでも読めないと困るし。!~とか非存在判定とか、Booleanの型変換を網羅的に知ってないと仕組み的にわからないよね。頭からそういうことが出来ると覚えちゃったほうが楽。

それにしても、厳密等価演算子、使いドコロがよくわからないな。厳密じゃないほうがキャストもしてくれるし楽できそうなんだが、それじゃダメな時があるんだろうな。まぁおいおい使っていくことにはなるんだろう。そういう所は経験が浅いので例示できない所が辛いところですが。


非同期処理に関しては、呼び出し直後に制御がもどっちゃうものをみんなそう言うらしい。そこいらへんがJavaScriptがnode.jsで重宝された理由なんだろう。setTimeout()などのタイマー系、Ajaxのとか、addEventLinstener()みたいなイベント処理系があるらしい。node.jsとかはイベントの処理系を主にさばく非同期処理なんだろう。それをつなぐ役目でAjaxがあるのかな。それとも全てAjaxとしてまとめてるのかな。動くものを作ったけど、必要に追われて処理を使ったわけじゃないので、理解がイマイチだ。そもそもがGUIのため、非同期処理ってのは当然の話の言語だったため、非同期処理を入れるのは難しくなかったんでしょうね。


クロージャが出てきた。前に出てきてよくわからなかったところ。最終的に分かったのは、インスタンス内で情報を保持して使いたかったら、中でvarで宣言して、関数を返すクロージャを使えば、個別インスタンスで状態を保持できるって事らしい。というか、そうしないと普通にインスタンスを他の言語のように使えないってことなんだろうな。レキシカル環境やスコープチェーンで説明しているけど、それって実装のところにかんできている気がするので、そこまで知らなくてもいい気がする。C言語のポインタは使うためには必修だが、JavaScriptで仕組みまでの知識は必要かどうか疑問だ。


あとは例外処理はC++とかと似てるからあんまり気にしなくていいけど、Errorオブジェクトで実装されていて、catch節でしかエラーオブジェクトは見られなくて、ブロックの外からは参照できないみたい。そもそもブロックの概念が他の言語より緩くて、グローバルと関数を入れ子にしてスコープを作らないといけないくらいだけど、なんか一貫性が全然ない。つーかES5も中間地点じゃないかとか思っちゃうんだけど。



詳しく見ていくうちに、他の言語で理解した常識が通じないところが多くあった。絶対ハマる要因になってくるよ、これ。本気でJavaScriptを使ってライブラリを作成しなくちゃいけなくなったら、最低のこの本の知識は必要になってくるとは思う。他の言語からズレてるなという、常識的な前提がないと覚えにくいと思うし、JavaScriptは最初のプログラミング言語とすべきではないと思った。動作環境はすぐに手に入れられるけど、ブラウザによってすこしずつ違うだろうし。規約が素直じゃないんだよな、基本的なところ見るだけでも。

それとこの本に言える事だけれども、少々他の言語の知識に頼り過ぎで説明不足なところがあるようだ。いきなりボクシングと言われても、Javaを知らない人には殴る方しか思い浮かばないだろうし、JavaScriptだと特殊なんだよという具体的な説明が不足している。多く説明しているから、必要なんだなとは感じたが、まるまる飲み込んで覚えるタイプの人にはあまり向いていない気がする。先にも言ったけど、レキシカル環境の挙動とか、コーディング時にはあんまり関係ないし、むしろJavaScriptを実装する人にしか余り意味がない気がするんだよね。ここでどこそこのポインタだから、メモリを開放するとか、JavaScriptを使う前提ではメモリを意図的に確保する事はないだろうから、もっと抽象的な概念で済むはず。


今度は斜め読みした部分を飛ばして、オブジェクト指向での大規模開発のところを見て行きたい。具体的に書いたわりには、理解の助けにならないものを書いちゃったので、今度はもっと噛み砕いてから書きますかね。そもそも、ライブラリを使う以外のオブジェクト指向はあんまり好きじゃない。




タグ:JavaScript
コメント(0) 
共通テーマ:パソコン・インターネット

コメント 0