1.6 命名ー 13 れます。 i 、 j 、 k といった 1 文字変数は、通常はループの中で使用されます。データ型を示唆 する名前を使うことで、自分だけでなく他の人が読んでも、コードがより簡単に理解できるよ うになります。 無意味な名前は避けるべきです。 f00 、 bar 、 temp といった名前は、開発者のツールポックス の一部であるとしても、変数に意味を与えません。他の開発者は、その変数名が何のために使 われているのか、コンテキストをすべて理解しないとわかりません。 関数とメソッドの名前については、最初の単語は常に動詞にすべきです。よく使われる動詞 がいくっかあります。 動詞 can has IS get set は味 プーリアンを返す関数 プーリアンを返す関数 プーリアンを返す関数 非プーリアンを返す関数 値を保存するために使われる関数 これらの規約に従うことで、コードはより読みやすくなります。いくっか例を見てみましょ つ。 if (isEnab1ed()) { setName("Nich01as"); "Nich01as") { if (getName() = d0Something() ; は値が可変であることを意味します ) と定数 ( ある値で初期化され、値が不変であることを意味 発者は、変数を定義してそれを定数として使うことを止めませんでした。正規の変数 ( これら ECMAScript 6 以前の JavaScript には、定数という概念がありませんでした。しかし、開 1.6.2 定数 値を設定します。それでもなお、関数名には動詞を使うことを推奨します。 "selected") は class 属性の class 属性の値を返し、 $("body"). attr("class" とセッターの両方で使われるからです。たとえば、 $("body"). attr("class") は 端は、 jQue Ⅳでのメソッドの使われ方にあります。メソッドの多くがゲッター jQuery は、関数についてのこの命名規則にまったく従っていません。理由の一 います。 が、 JavaScript 開発者の間ではほば標準となっていて、多くの人気あるライプラリで使われて 人気のあるスタイルガイドで、関数名に関してここまで詳しく定めているものはありません
グローバル変数 / 関数を作らない ロバティになります。次のコードを見てみましよう。 で、グローバルスコープにおいて宣言されたいかなる変数や関数も、 window オプジェクトのプ プラウザの場合、 window オプジェクトがグローバルオプジェクトにオーバーロードされるの キストを表現する神秘的なオプジェクトです。 わゆるグローバルオプジェクトの上に定義されています。スクリプトの最も外側にあるコンテ に利用可能になるさまざまなグローバル変数によって定義されています。これらはすべて、い の 1 つです。実際のところ、訂 avaScript のデフォルトの実行環境は、スクリプトの実行開始時 JavaScript の実行環境は、いろんな意味で独特です。グローバルな変数と関数の使い方がそ "red" var C010r function sayC010r() { alert(color); console. 10g ( window. C010 て ) ; console. log(typeof window. sayC010r); / / "function" グローバル変数 C010r とグローバル関数 sayCoIor ( ) が定義されています。どちらも window オプジェクトのプロバティとして明示的に設定していないにも関わらす、プロバティとして追 加されます。 6 コグローバル変数 / 関数の問題 グローバル変数 / 関数を作成するのは、一般にバッドプラクティスと見なされています。特に チーム開発の環境で問題になります。コードの開発が進むにつれ、グローバル変数 / 関数によ る決して小さくないメンテナンスの課題が多数発生します。グローバル変数 / 関数が増えるほ 、いくっかの共通問題が増加する傾向があるため、エラーが混入する可能性は大きくなり
A. 10 function do something() { / / コード 命名 ー 213 コンストラクタ関数 ( new 演算子を使ってオプジェクトを新規作成するのに使われる関数 ) は、 キャメルケースでフォーマットするが、先頭文字は大文字にする。オプジェクトインスタンス を作成するアクションが new であるから、コンストラクタ関数の名前は動詞以外で始める。 オプジェクトプロバテイも変数と同じ命名規則に従う。オプジェクトメソッドは、 var total COUNT = 10 ; / / Bad : ケースの混在 var totalCount = 10 ; / / Bad : キャメルケース var TOTAL COUNT = 10 ; / / Good はアンダースコア 1 文字で区切る。 定数として機能する ( 値が変更されない ) 変数は、すべて大文字でフォーマットし、その単語 / / コード function getMyObject() { / / Bad : 動詞で始まっている 〃コード function My_0bject() { / / Bad : アンダースコアが使われている / / コード function my0bject() { / / Bad : 小文字で始まっている / / コード function My0bject() { / / Good 関数と同 置きする。 じ命名規則に従う。プロバテイやメソッドをプライベートにしたいとき、アンダースコアを前
1 章基本フォーマット します ) を区別するために、一般的な命名規則が発展しました。 すべて大文字、単語の間はアンダースコアにします。 var MAX COUNT = 10 ; "http://www.nczonline.net/" ・ var URL = ・衄に由来する規約に従って、 これらの定数は、異なる命名規則を使っている変数にすぎないので、値を上書きすることが できてしまう点を念頭に置いておきましよう。通常の変数と定数は、 によって簡単に区別できます。次の例を考えてみましよう。 if (count く MAX COUNT) { d0Something(); このまったく異なる規約 ンスタンスを作成するために使われるので、通常は名詞になります。例を見てみましよう。 やコンストラクタ以外の関数から区別するのに役立ちます。コンストラクタ名は、ある型のイ anotherName の代わりに、 AnotherName を使います。こうすることで、コンストラクタを変数 PascaI ケースは、先頭文字が大文字である以外はキャメルケースと同じです。このため、 フォーマットされます。 様、コンストラクタはネイテイプ言語に従うので、コンストラクタは Pascal ケースを使って さらに開発者は独自のコンストラクタを追加して新しい型を作成できます。他の命名規則と同 単なる関数です。この言語には、 0bject や RegExp など多くのビルドインコンストラクタがあり、 JavaScript のコンストラクタは、 new 演算子を使ってオプジェクトを作成するのに使われる 1.6.3 コンストラクタ ( D 可 0 Style Guide は定数を Pascal ケースで指定することも許可しています。次節を参照 ) 。 Google 、 SproutCore 、 D 可 0 では、この方式で定数をフォーマットするように定めています クスが追加されます。 した変数であると、簡単にわかります。この規約によって、コードに別のレベルのセマンティ このコードでは、 count は値が変わる変数であり、 MAX COUNT は値が変わらないことを意図 / / Good function Person(name) { thiS . name name; Person. prototype. sayName alert(this. name) ; = function() { var me = new Person("Nich01as");
プラウザ特有のハックにコメントを付ける ポリフィル・ プラウザ推定 (browser inference) ・ プラウザ判定 (browser detection) 概要・・ 特徴検出・ 特徴推定・ プラウザ推定・・ ユーザ工ージェント判定・ プリミテイプ型 (primitive type) 概要・ 判定・・ プログラミング実践 (programming practice) nu Ⅱとの比較を避ける・ UI 層での疎結合・・ 234 ー索引 ファイルの連結 (concatenating files) 概要・・ 最終行の扱い ファクトリ関数 (factory function) フアサード (facade) ・ プーリアン (BooIean) ・ typeof 演算子・ プリミテイプ型としての ~ フォーマット規則 (formatting rule) 1 行の長さ・ インデントのレベル・・ 改行・ 関数呼び出しにおける空白・・ 空行・ 文の終端・ 命名規則 リテラル値・ 複数行コメント (multiline comment) ・ 複数行文字列 (multiline string) ・ 複文 (compound statement) ・ ブックマークレット (bookmarklet) ・ プラウザ (browser) addEventListener( ) 関数 Array. isArray( ) メソッド・ CSS 式・・ H andlebars templating システム・ message プロノヾティ <script> 要素 window オプジェクト YUI Test Selenium Server ・ 圧縮・ 工ラー処理・ オプジェクトの変更を妨げる・ 関数の判定・・ ・・ 26 , 204 ・・ 49 , 200 ・・ 11 , 212 ・ 155 ー 157 ・・ 86 ・・ 86 ・・ 119 ・・ 75 ・・ 156 ・・ 5 ー 7 , 199 ・・ 9 , 199 ・・ 49 , 85 ・・ 15 ー 20 ・・ 11 ー 15 ・・ 10 , 220 ・・ 43 ・ 125 ー 127 ・ 130 ー 133 ・ 127 ー 129 ・ 130 ー 133 ・・ 23 , 27 , 206 イベント処理・・ 工ラーを投げる オプジェクトの変更・・ 概要・ グローバル変数 / 関数を作らない 設定データをコードから切り離す・ プラウザ判定・・ プロック文 (block statement) 空白・ 波括弧 波括弧の位置を揃える・ プロトタイプ継承 (prototypal inheritance) ・ プロバティファイル (properties file) ・ 文 (statement) ・ 概要・・ 終端・・ 波括弧 波括弧の位置を揃える・ 複文・ プロック文での空白・ 文の終端 (terminating statement) ・ ・・ 31 ・・ 29 ・・ 30 ・・ 117 ・・ 97 ・・ 31 ・・ 215 ・・ 11 ・・ 29 ・・ 30 ・・ 215 ・・ 31 ・・ 79 ー 83 ・ 101 ー 109 ・ 111 ー 123 ・・ 51 ・・ 67 ー 78 ・・ 95 ー 99 ・ 125 ー 133 ・・ 16 ・・ 215 ・・ 78 ・・ 59 ・・ 90 ・・ 55 ・・ 64 ・・ 108 ・・ 63 ・・ 67 ・・ 181 ・・ 169 ・・ 102 ・・ 121 ・・ 89 ・・ 120 ・・ 125 ・・ 129 ・・ 53 ・・ 85 ー 93 ・・ 85 ー 87 変数 (variable) ・ ・・ 39 , グローバル変数とグローノヾル 関数も参照 nu Ⅱとの比較を避ける・ 改行・ 型強制 亠イ丁・ 宣言・・ 代入・ 命名規則 ・・ 85 ー 93 ・・ 10 ・・ 46 ー 48 ・・ 39 ー 41 , 69 , 208 ・・ 215 ・・ 12 ー 13 , 212 変数宣言の巻き上げ (variable declaration hoisting) ・・ 39 , 40 ホーア、 C ・ A ・ R(Hoare, C. A. R. ) ・ ポリフィル (polyfill) ・ ま行 密結合 (tight coupling) ・ ニフイケーションプロセス (minification process) CIosure CompiIer ・ UglifyJS ミニファイア・ YUI Compre ssor ・・ 概要・ 支援ツール・・ 無名関数 (anonymous function) 命名規則 (naming convention) 概要・ 関数・ コンストラクタ・ 定数・ ・・ 162 , 164 ー 166 ・・ 162 , 166 ー 168 ・ 161 ー 164 ・・ 13 ・・ 14 ・・ 12 ー 13 ・・ 51 ・・ 120 ・・ 161 ・・ 222 ・・ 44 ・・ 54
68 ー 6 章 ます。 グローバル変数 / 関数を作らない 6.1.1 名前の衝突 スクリプトにおけるグローバル変数 / 関数の数が増えるほど、名前が衝突する危険性が増し ます。すでに宣言した変数を誤って使ってしまうかもしれません。メンテナンスが最も容易な コードは、すべての変数がローカルに定義されているコードです。 たとえば、前の例の sayC010r ( ) 関数を考えてみましよう。この関数が正しく機能するには、 グローバル変数 C010r がなければなりません。もし saycol ( ) が C010 てとは別のファイルで 定義されていたら、エラーの原因を突き止めるのは難しくなるでしよう。 function sayC010r() { alert(color); / / Bad : これはどこから来た ? さらに、 C01 が複数の箇所で定義されていた場合、他のコードがこの関数をどのように取 り込むか次第で、 sayC010r() の結果が異なってしまうでしよう。 グローバルな環境はネイテイプの JavaScript オプジェクトが定義されている場所なので、 グローバルスコープに独自の名前を追加すると、将来プラウザがネイテイプで提供するかもし れない名前を使ってしまう危険があります。たとえば、 C010 てという名前は、明らかに安全な グローバル変数名ではありません。何の修飾もない平易な名詞なので、将来のネイテイプ API や別の開発作業で名前が衝突する可能性が高いでしよう。 6.1.2 コードの壊れやすさ グローバル変数 / 関数に依存する関数は、環境に密接に結合しています。もし環境が変わると、 その関数は壊れてしまうでしよう。前の例で、グローバル変数 C010r がもはや存在しない場合、 sayC010r() メソッドはエラーを投げるでしよう。つまり、グローバル環境での何らかの変化が、 コードのあちこちでエラーを発生させるかもしれないのです。また、グローバル変数 / 関数は、 関数によってどこからでも変更できてしまうので、その値の信頼性は著しく損なわれます。前 の例の関数は、 C010r を引数として渡せば、大幅にメンテナンスしやすくなります。 function sayC010r(c010r) { alert(color); このバージョンの関数はグローバル変数に依存しないので、グローバル環境に変化があって も、影響を被りません。 C010r は引数なので、問題になるのは関数に渡された値が妥当かどうか だけです。それ以外に変化があっても、この関数が仕事を完了する上で何の影響もないでしよう。 関数を定義するときには、データは可能なかぎりその関数に対してローカルにしておくのが ベストです。関数の内部で定義できるものはすべて、そのように書かれるべきです。その関数 の外側からやってくるデータは、引数として渡すべきです。このようにして関数を、それを取
44 ー 4 章変数、関数、演算子 生 4 即時関数呼び出し JavaScript では、無名関数 ( 名前のない関数 ) を宣言し、これらの関数を変数やプロバティ var doSomething = function() { に代入することができます。 / / Bad きます。 / / 関数本体 こうした無名関数は、最後に括弧を置くことで、即座に呼び出し、変数に値を返すことがで message: return { / / 関数本体 var value = function() { この例では、関数が即座に呼び出されるので、 value には最終的にオプジェクトが代入され ではこのパターンが推奨されていますが、訂 SLint は括弧がないとき警告します。 弧を追加しても、このコードの振る舞いは一切変わりません。クロックフォードのコード規約 このコードには 1 行目にシグナルとなる開き括弧があり、関数が即座に呼び出されます。括 = (function() { message: return { / / 関数本体 var value / / Good りましよう。 即時関数呼び出しが発生することを明確にするために、次の例のように、関数を括弧でくく この種の混乱は、コードの可読性を損ないます。 で見て、括弧があることを確認しないと、それが無名関数の即時呼び出しだとわかりません。 ます。このパターンの問題は、変数への無名関数の代入と非常に似ている点です。最後の行ま
6.2 誤ってグローバル変数が作られる一 69 り巻く環境から切り離せば、関数の変更も環境の変更も、どちらも他に影響を与えることなく 可能になります。 6.1.3 テストが難しくなる 大規模なウエプアプリケーションの 1 つで単体テストをいくっか実装したことがあります。 そのチームに参加したときには、最もコアなフレームワークの構築はすでに完了していて、テ ストをいくつか作成するために、全体がどのように動作しているのか深く理解しようとしまし た。テストの作成が極めて困難な作業になることがわかり、落胆させられました。フレームワー ク全体が正しく動作するためには、いくっかのグローバル変数に依存していたからです。 グローバル変数に依存する関数があると、その関数を正しくテストするためにグローバル環 境全体を再作成しなければなりません。実際のところ、これは 1 つのグローバル環境での変化 を管理しているのではなく、プロダクションとテスト、この 2 つのグローバル環境でその関数 を管理していることを意味します。これらを同期させるコストが加わり、容易に解けないメン テナンスの悪夢が始まるのです。 あなたが作成する関数がグローバル変数 / 関数に依存しなければ、作成するコードのテスト 可能度が向上します。もちろん、作成する関数は、 Date 、 Array など、 JavaScript にネイティ プなグローバル関数に依存しています。 JavaScript 工ンジンのおかげで、これらは常にグロー バル環境の一部です。作成する関数は、いくっかのグローバル変数 / 関数が存在することを常 に前提して構いません。しかし、最善のテスト可能度を保証するために導入したグローバル変 数にあなたが作成する関数が依存するようになるのは許されません。 6.2 誤ってグローバル変数が作られる JavaScript で表面化しにくい問題の 1 つは、誤ってグローバル変数を作成してしまう点です。 それ以前のコンテキストでまだ va て文で定義されていない変数に値を代入すると、 JavaScript は自動的にそのグローバル変数を作成します。たとえば、次のコードは、誤ってグローバル変 数を導入してしまう、よくあるコーディングエラーを示しています。 function d0Something() { var count = 10 ; title = "MaintainabIe JavaScript" ・ / / Bad: これはグローバル おそらく var 文を使って 2 つの変数を宣言したかったのでしようが、最初の変数の後がカン マではなく、誤ってセミコロンになっています。その結果 title がグローバル変数として作成 されてしまいます。 この問題は、グローバル変数と同じ名前でローカル変数を作成しようとするとき、複雑にな ります。たとえば、前の例では、 count という名前のグローバル変数があった場合、ローカル
78 ー 6 章グローバル変数 / 関数を作らない している場合や、スクリプトが小さく、ページに挿入されるスクリプトがページに干渉すべき でない場合が該当します。最も使われるユースケースはブックマークレットの作成です。 ブックマークレットは、ページで何が置きているのか、まったく知らない点、そしてブック マークレットが存在することをベージに知らせたくない点が、他にない特徴です。最終結果は、 スクリプトを 0 ーグローバルで組み込む必要があり、これは即時関数呼び出しを使い、すべての スクリプトを関数内部に記述することで実現します。 (function(win) { var dOC = Win. document; }(window)); ここに別のコード / / 別の変数をここで宣 var dOC = Win. document; use stricttt (function(win) { ることでグローバル変数の作成を避けることもできます。 挿入しません。 ( プラウザが strict モードをサポートしていれば ) 関数を strict モードにす キーワードを使って宣言されているかぎり、このスクリプトはグローバル変数を一切ページに の参照を保持します。この関数が window や doc を直接変更することなく、すべての変数が va て 接アクセスする必要がありません。この関数の内部では、 doc 変数が document オプジェクトへ window オプジェクトを渡して関数を即座に呼び出すので、スクリプトはグローバル変数に直 }(window)); ここに別のコード / / 別の変数をここで宣 リプトがあるときには、 0 ーグローバルアプローチが使えることを覚えておきましよう。 チを使えません。しかし、ページ上で他のスクリプトとの相互作用が一切必要ない小さなスク せん。実行時に拡張したり変更したりしなければならないスクリプトも 0 ーグローバルアプロー 他のスクリプトから使われる必要があるスクリプトには、 0 ーグローバルのアプローチは使えま 使えます。すでに指摘したように、このパターンが使える局面は限られています。ページ上で グローバルオプジェクトを一切作成したくないときには、この関数ラッパーをスクリプトで
40 ー 4 章変数、関数、演算子 value = 10 ; return result; 2 つの va て文は関数の先頭に巻き上げられています。その後で初期化が行われます。変数 value が 6 行目で使用されるとき、その値は特殊な undefined になります。このため result は NaN ( 非数値 ) になります。その後で value には最終的に 10 が代入されます。 for 文での変数宣言の巻き上げは、開発者が見落とす傾向にあります。 for 文では変数が初 期化の一部として宣言されています。 function d0SomethingWithItems(items) { f0 て (var i=0, len=items. length; i く len; i + + ) { doSomething(items[i]); ECMAScript 5 までの JavaScript には、 このコードは実際には以下と同等です。 function doSomethingWithItems(items) { var i, len; プロックレベル変数宣言の概念はなかったので、 f0 て (i=O, len=items. length; i く len; i + + ) { d0Something(items[i]); 変数宣言が巻き上げられるということは、関数の中のどこで変数を定義したとしても、関数 の冒頭で宣言したのと同じになるということを意味します。このため、関数内のあちこちに変 数宣言を散乱させるのではなく、すべての変数を関数の冒頭で宣言しておくのは人気のあるス タイルです。手短に言えば、 JavaScript 工ンジンがコードを解釈するやり方に近いコードを書 くことになります。 関数の最初の文でローカル変数を定義しておくのを本書は推奨します。このアプローチはク ロックフォードのコード規約、 SproutCore 、 D 可 0 でも推奨されています。 function d0SomethingWithItems(items) { var result var value var i, len; = value + 10 ; = 10 ;