随時更新。
*ES5までのコーディングポイントです。
プリミティブ型は値渡し、オブジェクト型は参照渡し
プリミティブ型以外は参照元に変更が伝播する。
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 || '女性' //男性