Javascriptでコーディングする際のポイント

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

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

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

このように参照元に変更が伝播する。
これが原因で意図しないバグが出るとかよく聞く話。


2. for in は使わない

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ユーザー

ただ if文 が入るのでネストが深くなる。
ついでに ほぼ影響はないだろうけど全プロパティに評価が実行される問題もある。(速度にほとんど影響はでないだろうけど...)

なので こっちを使う。

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

こっちの方がスッキリしてるし何より Cool!!

え....for i ?
....知らない子ですね

3. Object型のディープコピー

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

ちなみにコピーなので変更による伝播は無い。

copy_user.call = function(){console.log("メソッド書き換え")};

user.call(); //hogehoge
copy_user.call(); //メソッド書き換え

3. == と ===

== の比較演算子は恐ろしい挙動をとる。

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

どちらが安全なコーディングかは一目瞭然。
とりあえず == を使っているようなら === に書き換えることを お勧めする。

4. グローバル変数の削減

グローバル変数の宣言はアプリケーションで一つのみに制限することが最も良い。

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

このようにグローバル変数を一つに限定し、
以降 実装に必要な変数は全てグローバル変数のプロパティとして宣言すればいい。
そうすることでグローバル変数の問題から開放されストレスの無いコーディングが可能になる。
注意点としてはグローバル変数から全プロパティにアクセス可能なため
外部からアクセスされたくないメソッド、変数がある場合はクロージャ等で外部からアクセスできないようにする必要がある。