Hatena::ブログ(Diary)

杉風呂2.0 - A Lifelog -

2011-11-17(木)

[]あなたはJavaScriptを知らない

この記事はMichael Woloszynowicz氏のブログWeb 2.0 Development And Business Lessonsの記事"You Don’t Know JavaScript"を翻訳したものです。本人の許可を得て公開します。原文は2011年4月16日にポストされました。私自身のJavaScriptの学習が浅く、誤訳の指摘等はコメントを下さると助かります。

原文は以下のURLから。

http://www.w2lessons.com/2011/04/you-dont-know-javascript.html

去年ぐらいから、いらいらする現象が目に留まるようになった。プログラマが、少ししか触っていない技術でありながら、それで履歴書を脚色するパターンに何度も出会った。多くの言語で起こることではあるが、最も冒涜を受けている言語がJavaScriptだ。

あなたは自分が知らないということを知らない

この理由は、だいたいすべてのWeb開発者が1つぐらいはJavaScriptを扱う必要に出くわすからだ。理解もしないでJavaScriptを憶える最もありふれたアプローチとして、その場しのぎにサンプルコードを探してきてコピペするのだ。この手の'学習'で問題なのは、開発者が実際にはその言語を学んでおらず、その上、自分がそれを知っている錯覚してしまうことだ。何年もJavaScriptで仕事をして学んできた過程でわかったのは、本当に理解するようになってはじめて、知らないということがわかるということだ。このことはある種、循環した話であり、あなたに本当に必要なのは、自分がわかっていないということを教えてくれる人であり、本当の学習だ。サンプルコードをつなぎあわせただけの単純なonClickハンドラやformバリデーションしかやったことがないのに、誇らしげにJavaScriptを履歴書にリストアップした誰かさんとたくさん面接をしすぎている。jQueryDojoのようなフレームワークを使い知るということはいいことだが、それらの背後にあるJavaScriptを正しく理解することなしには、それらのツールキットをマスターすることはないだろう。JavaScriptの多くの要素を表現するのに、私が基本レベル、中級レベル、上級レベルの知識だと思う考えを以下に示す。

JavaScript理解の基本レベル

  • 基本的なプログラミングのツール、例えば、ループやifステートメント、try/catchなどを知る。
  • 関数定義と適用に様々な方法があることを知る。無名関数も同様。
  • 基本的なスコープ定義の原則、グローバルスコープ(window) 対オブジェクトスコープ(closure)を理解する。
  • コンテキストの役割とthis変数の使い方を理解する。
  • オブジェクトインスタンス化と宣言の様々なやり方を理解する。関数オブジェクトであるということも同様。
  • JavaScriptの比較演算子、例えば、'<'、'>'、'=='、'==='で何がfalseになるか、オブジェクトとstringがどのようにして比較されるかを理解する。キャストも同様。
  • Arrayがオブジェクトの属性と関数をどうインデクシングしているかと、それが本当の配列とどう違うか。(オブジェクトリテラル対配列リテラル)。

JavaScript理解の中級レベル

  • タイマーがどう動くか、つまり、いつどのようにして利用できるようになるかを理解する。非同期メソッド呼び出しも同様。
  • コールバックと関数適用を深く知る。例えば、'call'と'apply'メソッドでコンテキストを操作して、関数引数として渡すことなど(function argument passing)。
  • JSON記法とeval関数を理解する。
  • クロージャがコードのパフォーマンスにどのように影響し、プライベート変数を作成するのにどのように利用されるかを理解する。
  • 愛くるしい(lovely)、(function(){})() 呼び出しに慣れ親しむ。
  • AJAXオブジェクトシリアライズ

JavaScriptの理解の上級レベル

(訳注:この段落は具体的な状況があまり思い浮かばず、かなり怪しい部分もあるのでJS上級者は原文を参照ください。)

  • メソッドのarguments変数を理解し、それがどのように使われて、arguments.lengthによって関数のオーバーロードを行えるかや、arguments.calleeによって再帰呼び出しを行えるか。arguments.calleeの使用が、ECMAScript 5のStrictモードがサポートしていない*1ことからもわかるように、危険なことだということを付け加えておこう。jQuery(バージョン1.4まで)とDojoの両者がそれを利用していようともだ。
  • 自己メモ化、カリー化、関数の部分適用のような高等なクロージャの使い方
  • 関数htmlプロトタイピング、つまりプロトタイプチェーンと基本的なJavaScriptオブジェクト関数(例:Array)を使ってコードを小さくすること。
  • Object型、instanceofとtypeofの使い方
  • 正規表現正規表現コンパイル
  • withステートメントと、なぜそれを使うべきでないか
  • 最も難しいのは、それらのツールすべてを結びつけて、きれいで(clean)、堅牢で、速くメンテナンスしやすい、クロスブラウザ対応のコードに仕上げることだ。

上級レベルの最後のポイントはとりわけ重要であり、最も到達するのが難しい。JavaScriptの怠慢な性質を考えれば、自分のアプリケーションをメンテナンスできないスパゲッティコードの悪循環へとたやすく陥れてしまう。いったんJavaScriptという言語自身を学べば、それを体系化し、大きなアプリケーションのコンテキストにおいて互いに結びづけることができるようになって、真にマスターできるだろう。それには数年間の訓練と失敗が必要であり、本1冊では精通することができない。私自身は、JavaScriptを日常的に毎日数時間、数年間使用していて、自分のコードを書くのにより良い方法を見つけようとし続けているところだ。

こういった理由で、なにかのフレームワークに一足飛びにジャンプすることは危険であるし、jQueryのコードはメンテナンス不可能になる傾向がある。Dojoは自身のクラスとパッケージシステムによって、これを助長する。

JavaScriptNode.jsなどによりいまやバックエンドまで浸透しているので、上に挙げた要件は、web特有の知識から分離することにした。webの側面(つまりDOMIE)はJavaScriptに悪い名前を与え、すべてのプログラマを震え上がらせ、くらくらさせてきた。JavaScriptをwebのコンテキストで使おうとするならば、すべての良い開発者が知るべき追加事項が存在する。

  • DOMとそれを効果的に操作すること。つまり、追加、削除、ノードの変更だ。テキストノードも同様。
  • Document fragmentのようなツールを使って、ブラウザの再走査(re-flow)を最小限にすることを含む。
  • クロスブラウザに対応した方法でDOMから情報を抽出すること(例:style、positionなど)。このようなことは、jQueryDojoなどのフレームワークで非常にうまくなされているが、CSS対styleタグに代表されるような情報を抽出することと位置やサイズを指定することの違いを理解することが重要だ。
  • クロスブラウザ対応でイベントをハンドリング、バインディング、アンバインディング、バブリング、つまり、望みのコールバックコンテキストを達成する方法。重ねて言うが、これはフレームワーク経由であれば、非常にうまくハンドリングされているが、個人でもIEW3C標準のブラウザとの違いを理解するべきだ。
  • Expando対attribute設定とそれらのパフォーマンスが違い、名称との不一致(naming discrepancies)があるということ。
  • DOMノードを抽出する正規表現
  • ブラウザの機能を効果的に検出して、それらを上品に剥奪すること(graceful degradation)。

上記のリストからわかることは、JavaScriptには、alert(myVal)やmyBtn.onclick = ...以上のものがたくさんあるという地獄が存在するということだ。コピペできる以上のことがかなり多く存在するし、書籍を読み訓練することでしか本物のJavaScriptプログラマになることことはできない。これらすべてのトピックをカバーする偉大な書籍が『JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス』と『Secrets of the JavaScript Ninja』だ。思い出してほしい。JavaScriptが最もアクセスしやすい言語で、誰もがブラウザを持っていて、セットアップの時間すらかからないということを。シンプルなHTMLページを作って、上に挙げた概念(concepts)と戯れ始めよう。履歴書の脚色についてだが、初心者レベルをカバーして、中級レベルに飛び込んでいれば、JavaScriptをリストに加えてもよいと認めよう。コピペしないで、自分が望んだ機能(function)を開発していることに気づいたなら、JavaScriptを知っていると主張できる。それまではJavaScriptを知っているなどと宣伝しないでほしい。

私が書き損じたJavaScriptの側面があれば、コメントから知らせてほしい。また、JSや他の言語を知っていると主張する人に出会った経験を共有してほしい。

付け加えておくと、私はフロントエンド開発者ではなく、バックエンド開発者であり、フルスタック開発者へと進化してきた。今日では、ほとんどすべてのバックエンド開発者はJavaScriptを学ぶ必要があり、それがこの記事の意図するところだ。見下そうという意図はなく、JSにあるものすべてを知れと主張するわけではない。私の希望は、JavaScriptは広大でパワフルな言語で、見た目以上のものがあるのだと、より多くの人が気づいてほしいということだ。

もし、このポストを気に入ったらTwitter私をフォローしてほしい。

*1:2011/11/19追記 以下も参考にしてください。Togetter:arguments.calleeがstrictモードで禁止な理由

なすなす 2011/11/17 11:01 基本レベルの1つめの「jfステートメント」ってのはifの間違いではありませんか;

teramakoteramako 2011/11/17 12:02 「JavaScriptの理解の上級レベル」部分:
うまい日本語訳は分かりませんが、『具体的な状況が思い浮かばず』と書かれていたので補足として。

"how it can be used to overload functions through arguments.length ..."

Javaなどの言語だと同名のメソッドで別の引数の数や型を受け付けるメソッドを定義するのをoverloadと言いますが、これを表現するためにoverloadという言葉が使われているのだと思います。

function foo(a,b){
var args = [];
for (var i = 0; i < arguments.length; ++i) {
args.push(arguments[i]);
}
}

fooという関数宣言では引数a,bの二つを設定していますが、JavaScriptでは引数の数や型は何でもOKですので、foo(1,2) は当然ながら、foo(1,2,3,4,5,6) の様な事もできます。
arguments変数には a, bに入る値以外にも全ての値が入っている(arguments.length個)ので、一つのメソッドでさまざまな引数の数に対応できるということを言いたい文だと思います。



また、"It should be noted that 〜" 部分ですが「〜を記しておかなければならないだろう。⇒〜を記しておこう。」の意として取りましたが、どうでしょうか。

suginoysuginoy 2011/11/17 12:41 >なすさん
typoでした。ありがとうございます。

>teramakoさん
解説ありがとうございます。
なるほどよくわかりました。
shouldもid:teramakoさんので正しいと思います。

Connection: close