JavaScriptのコーディングポイント【ES5まで】

随時更新。
＊ES５までのコーディングポイントです。

# プリミティブ型は値渡し、オブジェクト型は参照渡し

プリミティブ型以外は参照元に変更が伝播する。

```
var user = { "name" : "サンプルユーザー" };
var copy_user = user;

copy_user.name = "更新ユーザー" //Object {name: "更新ユーザー"}
user //Object {name: "更新ユーザー"}
```


# for in は基本的に使わない

for in はprototypeが汚染されていた場合に以下の様なバグを引き起こす。

```
Object.prototype.bag = "プロトタイプを汚染";
var user = {};
user.name = "SAMPLEユーザー";
for(var key in user){console.log(user(key))} //SAMPLEユーザー , プロトタイプを汚染
```

対策としては hasOwnProperty を使えば問題ない。


```
for(var key in user){ if ( user.hasOwnProperty(key)) console.log(key) }//SAMPLEユーザー
```

けどネストが深くなるし、綺麗じゃない。
なので、Object.keysを利用したループを使う。

```
Object.keys(user).forEach(function(key){console.log(key)})
```

# オブジェクトのディープコピー

JavaScriptではobjectをディープコピーするメソッドは用意されていない。
JSONを使って複製する方法はあることにはあるが、実は完全な(?)ディープコピーでは無かったりする。

```
var user = {};
user.call = function(){console.log("hogehoge")};
user.call() //hogehoge
var copy_user = JSON.parse(JSON.stringify(user));
copy_user.call(); //copy_user.call is not a function(…)
```

このようにfunctionが破壊されてしまっている。
多分ネイティブのみでディープコピーをしようとすると自前でメソッドを実装するしかない。
面倒なら、JQueryの$.extendを使って解決する。

```
var user = {};
user.call = function(){console.log("hogehoge")};
user.call(); //hogehoge

var copy_user = $.extend(true,{},user);
copy_user.call();//hogehoge
```

#  == と ===

JavaScriptの == 演算子は不安定なので可能な限り使わない。

```
23 == "23" //true
null == undefined //true
0 == '' //true
false == '0' //true
false == 0 //true
```


```
23 === "23" //false
null === undefined //false
0 === '' //false
false === '0' //false
false === 0 //false
```

一応 == は undifind判定で使ったりはする。
とりあえず == を使っているようなら === に書き換えることを お勧めする。

# グローバル変数の削減

グローバル変数を一つに限定し、
以降 実装に必要な変数は全てグローバル変数のプロパティとして宣言する。

```
var Main = {};
Main.UserModel = {......}
Main.UserController = {.....}
```

#  関数内で引数を参照
関数内で自身に渡された引数を参照したい場合 arguments を参照する。

>arguments はすべての関数内で利用可能なローカル変数です。arguments オブジェクトを使うことにより、関数内で関数の引数を参照できます。このオブジェクトは、関数に渡された各引数に対する入力を含みます。最初の入力の添え字は 0 から始まります

argumentsはlengthプロパティのみをもつObjectであるためArrayのように扱うには一旦Arrayに変換する必要がある。

```
var avg = function(){
	var stack = 0;
	Array.prototype.slice.call(arguments).forEach(function(num){
		stack += num;
	});

	return stack/arguments.length
}

avg(20,10,30) //20
```


# Arrayメソッドを適切に扱う

Arrayオブジェクトの処理はforEachだけではなく
処理に合った適切なメソッドを利用する。

- 一つでも条件を満たすか判定

```
['10','20','30'].some(function(value){
  return value.match(/^1/);
})
//⇒true
```

- 全ての条件を満たすかを判定

```
['10','20','30'].every(function(value){
  return value.match(/0/);
})
//⇒true
```

- 左から順番に処理をした結果を返す

```
['10','20','30'].reduce(function(before, after){
  return before+after;
})
//⇒102030
```

- 右から順番に処理をした結果を返す

```
['10','20','30'].reduceRight(function(before, after){
  return before+after;
})
//⇒302010
```

- 指定の処理を行い、結果を新規配列で返す

```
var result = ['10','20','30'].map(function(value){
  return (+value)+1
})
//⇒[11, 21, 31]
```

- 条件を満たしたもののみ抽出し、新規配列を返す

```
var result = ['10','20','30'].filter(function(value){
  return (+value) >= 20;
});
```


# 番外編

処理には直接関わらないイディオム的なもの。

## 複数の変数定義で var を省略 
複数の変数定義は , で繋げることで var を省略することができる。
最終定義で必ず ; 入れる必要がある。
※ lintを入れるとエラーになるケースもあるので注意

```
var a = new Date(),
    b = [],
    c = {};
```

##  null ガード
null or undefined をガードする。
ただし変数自体が未定義の場合はエラーを返すため注意。

```
var user = {},
    name,
    type = '男性';

user.name = name || 'ゲスト'; //ゲスト
user.type = type || '女性'    //男性
```