Javascriptのコーディングスタイルを復習 - Google編


今回は、[Google Javascript Style Guide](http://cou929.nu/data/google_javascript_style_guide)を眺めて、重要そう・忘れがちなトピックのみを抜粋しました。

サンプルコードは原文通りではなく、理解促進のために簡潔な形に修正しています。

## 言語仕様に関わるルール

### ブロック内で関数宣言してはならない
ブロック内において、関数を利用する場合は変数に代入して利用する事。

```javascript
// for, switchなども同様
/* 非推奨 */
if (x) {
  function foo(){}
}

/* 推奨 */
if (x) {
  var foo = function() {}
}
```
理由は、単にECMAで標準化されていないため。
（実行環境に依存、あるいは将来的に動かなくなる可能性を持っている）

### プリミティブ型のラッパーオブジェクトを利用しない
様々なケースの弊害が想定出来るが、典型的なのは真偽値を期待していたのに、真偽値ではなくなっていたパターンだと思う。

```javascript
/* オブジェクトの真偽値判定は常にtrue */
var x = new Boolean(false);
if (x) console.log(x); // -> Booleanオブジェクト

/* これはOK */
var x = Boolean(0);
if (!x) console.log(x); // -> false
```

**プリミティブ型のコンストラクタはnewしてはならない**

### メソッドとプロパティの定義
インスタンス化されたオブジェクトに追加するのではなく、コンストラクタ内におけるプロパティの初期化・プロトタイプによるコンストラクタへのメソッド追加が推奨される。

### `delete`演算子を利用せず、`null`を代入する
プロパティ数の変更より、再代入の方が実行パフォーマンスが優れるため。

```javascript
foo = {
  bar: {
    baz: {}
    ...
  }
}

delete foo.bar;
console.log(foo.bar); // -> undefined

foo.bar = null;
console.log(foo.bar); // -> null
```

### this
コンストラクタ、およびオブジェクトのメソッド内（クロージャの作成含む）のみ許容

### 連想配列
配列のインデックスに数値以外の値を適用して、map/hashのようなデータを作成しない事。
map/hashを利用したいときは、オブジェクトを利用する。

### 複数業のstringリテラル
文字列内に`\`を用いて改行を表現しない事。
改行を表現する場合、`+`演算子で連結する。

```javascript
/* 非推奨 */
var multiLineStr = 'hoge\
            fuga';
            
/* 推奨 */
var multiLineStr = 'hoge' +
           'fuga';
```

### ビルトインオブジェクトのプロトタイプ書き換え
言語仕様が変わってしまうような操作は行わない。

### IEの条件付きコメントは利用しない
動作が遅くなるため。


## スタイルに関わるルール

### 命名規則

```javascript
 // 関数、変数、メソッド、名前空間はキャメルケース
somethingName
// コンストラクタはパスカルケース
ClassName
// 定数は大文字スネークケース
CONSTANT_NAME
// privateプロパティ、メソッド(protectedはpublicと同様)
_privateMethod
// オプション引数(必須ではないパラメータ)にはopt_プレフィックスを付ける
opt_param
// 可変長引数はvar_arg固定、かつ関数内ではargumentsを参照
var_arg
// ファイル名は全て小文字
filename.js
```

### getter/setterを利用しない
利用したい場合は、`getFoo/setFoo`のような名前にしてあげる。

### 長い型名のエイリアスを作成する

```javascript
app.namespace.MyClass = function() {}
myApp = function() {
  var MyClass = app.namespace.MyClass;
}
```

### 開始波括弧は宣言と同じ行に配置する（改行しちゃだめ）

```javascript
/* 推奨例 */
if (x) {
}
```



### 配列・オブジェクトの初期化

```javascript
// 1行の場合(80文字)、括弧の前後には空白を挿入しない
var obj = {a:1, b:2}
//複数行の場合は括弧だけで1行つかう、かつインデントはスペース2つ
var obj = {
  foo: 1,
  bar: 2
}
// キー名が長い場合、`:`を整列させない
var obj = {
  foo: 1,
  barbaz: 2
}
```

### 引数  
可能な限り1行に納める。  
80文字を超えた場合は、折り返しても良い。  
また、1行づつ配置しても良い。

```javascript
// スペース4つ分インデントし、80字で折り返し
// 関数をリネームしてもインデントを修正しなくてOK
app.namespace.foo = function(
  foo, bar, ...省略..., baz,
  hoge, huga, ...省略..., piyo) {
};

// 丸括弧にそろえて80字で折り返す
function somethingFunc(foo, bar, ...省略..., baz,
            hoge, huga, ...省略..., piyo) {
};

// スペース4つ分インデントし、各業に1つずつ引数を記述
// 引数名が長い場合に有効
app.namespace.foo = function(
  fooBar...省略...Baz,
  hogeHuga...省略...Piyo) {
};
  
// 丸括弧に揃えてインデントし、1行毎に引数を記述
function somethingFunc(fooBar...省略...Baz,
              hogeHuga...省略...Piyo) {
};
```

### 無名関数を引数とする場合
内容を文全体の左端からスペース2つ分インデントする。  
または、無名関数宣言の左端から2つ分インデントする。

```javascript
app.namespace.somethingFunc(function() {
  var x = true;
  if (x) return 1;
});
  

var somethingFuncClojure = app.namespace.somethingFunc(
    fooBarBazParam,
    hogeFugaPiyoParam,
    function() {
      var x = true;
      if (x) return 1;
    });
```

恐らく、無名関数によるコールバックの宣言はネストが深くなるため2行なんだと思われる。

### 式を折り返す際のインデント  
行を折り返す場合は、直前の兄弟式の左端に開始位置を揃える。  
または、スペース4つ分のインデントを挿入する。  
(配列、オブジェクト、無名関数の引き渡しはスペース2つ分)

```javascript
// 直前の兄弟式の左端に開始位置を揃える
var html = 'fooBar...省略...Baz' + 
           'hogeFuga...省略...Piyo';

// 直前式の左端から4スペース
app.namespace.fooBar...省略..Baz =
    hogeFugaPiyo;
```

### 空白行  
論理的なまとまりを表すため適宜、空白行を挿入する

```javascript
var preParam = 'pre';
preSomething(preParam);

var nowParam = 'now';
nowSomething(nowParam);

var afterParam = 'after';
afterSomething(afterParam);
```

### 二項・三項演算子  
演算子は常に先行する行に配置する

```javascript
// 一行で収まる場合はこのように記述
var x = a ? b : c;
 
// 4文字分のインデントでもOK（?を先行する行に配置）
var y = a ?
    longButSimpleOperandB : longButSimpleOperandC;
 
// 最初のオペランドの位置までインデントする形でもOK
// （?と:を先行する行に配置）
var z = a ?
        moreComplicatedB :
        moreComplicatedC;
This includes the dot operator.

// ドット演算子も同様（.を先行する行に配置）
var x = foo.bar().
    doSomething().
    doSomethingElse();
```

### 丸括弧
構文上必要となる箇所のみに記述

### 文字列
常にシングルクォーテーション`'`を利用
(htmlを含む文字列を作る際に有効)


## Tips・トリック

### 真偽値表現
下記はfalseになる

- null
- undefined
- ''(空の文字列)
- 0

下記はtrueになる

- '0', 'null', 'undefined'(空でない文字列)
- [], {} (空の配列、オブジェクト)