JavaScriptって、動きが想定外な時ってありませんか?
思い込みで動かしていて、なんかバグが出ていると思うと実はJavaScriptの仕様だったということがいくつかあります。
「JavaScriptめ!」と言ってしまいたくなる仕様(つまり、バグの温床になりそうな仕様)をリストアップしてみました。
頭に入れておくだけで、バグにならずに済むと思います。
1. 配列・オブジェクトが参照渡し
JavaScriptの配列・オブジェクトは値渡しではなく、参照渡し。
これを、知らないと痛い目を見る・・・
var ary = [1,2,3,4,5,6];
var obj = {0:1,1:2,2:3,3:4,4:5,5:6};
ary2 = ary;
obj2 = obj;
ary2.splice(0,1);
delete obj2[0];
console.log(ary); // 更新されている => [2, 3, 4, 5, 6]
console.log(obj); // 更新されている => {1: 2, 2: 3, 3: 4, 4: 5, 5: 6}
なので、値渡しでコピーしたい時に、forで回したり、JQueryで処理したりと色々あるが、個人的に落ち着いた方法はJSONにして、parseする方法
ary3 = JSON.parse(JSON.stringify(ary));
obj3 = JSON.parse(JSON.stringify(obj));
ary3.splice(0,1);
delete obj3[0];
console.log(ary); // 更新されていない => [1, 2, 3, 4, 5, 6]
console.log(obj); // 更新されていない => {0:1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6}
2. オブジェクトがKeyで勝手にソートされる
Keyのつけ方を工夫しないといけない。
var obj = {5:1,4:2,3:3,2:4,1:5,0:6};
console.log(obj); //{0: 6, 1: 5, 2: 4, 3: 3, 4: 2, 5: 1}
参考:JavaScriptの配列がキー値で自動ソートされてしまう件
3. テキスト置換( .replace() )が1つ目の対象しか対応できない
JavascriptのString.replace() はglobalじゃない
var test = 'abc_def_abc';
console.log(test.replace('abc','xyz')); // xyz_def_abc
正規表現にする
console.log(test.replace(/abc/g,'xyz')); // xyz_def_xyz
4. ブラウザによって挙動が異なる
これは、コードレベルではないのでコメントだけ。
JavaScriptはブラウザによって挙動が異なることがある。
特にIE。
それ以外にもブラウザで異なるので注意が必要。
JavaScriptの仕様である ECMA Scriptに沿った組み方を意識しつつ、挙動を各ブラウザで確認する必要がある。
5. セミコロンの自動挿入
JavaScriptの緩い仕様。
文の終わりを示す、セミコロンを自動挿入してくれてしまう。
var a = 1
//これは、以下になる
var a=1;
そうすると、return を改行してしまった時、
return
a
//これは、以下になる return がnull
return;
a;
お節介いらないので、セミコロンなければ、最初からエラー吐いて欲しい。
6. ローカル変数の宣言位置による仕様
あまり出くわさないけどやってしまいそうな仕様。
var a = 'global';
var func = function() {
alert(a);
var a = 'local';
};
func(); // undefined
//これは以下と同じになるらしい
var func = function() {
var a; // undefinedで宣言
alert(a);
a = 'local';
};
何これ。
7. 日付処理の月が0から11
これは見た方が早い。
var dt = new Date(); //今日が9月22日だったとすると
alert(dt.getMonth()); // 8
何これ。
8. オブジェクトと配列で削除方法が異なる
オブジェクトと配列は意識して使い分けなければならない、という当たり前のようで、よくエラーを起こしがちな所。
var ary = [1,2,3,4,5,6];
var obj = {0:1,1:2,2:3,3:4,4:5,5:6};
ary.splice(3,1); //削除される
obj.splice(3,1); //errorになる
delete ary[3]; //削除されるがlengthは変わらない
delete obj[3]; //削除される
9. オブジェクトと配列のlength
オブジェクトと配列は意識して使い分けなければならない、その2
オブジェクト.lengthはundefinedになる
var ary = [1,2,3,4,5,6];
var obj = {0:1,1:2,2:3,3:4,4:5,5:6};
console.log(ary.length); //6
console.log(obj.length); //undefined
console.log(Object.keys(obj).length); //6
なぜ、返してくれないのか。。。不親切だ。
また、こんな仕様もあるらしい。
var arr = new Array();
arr[0] = "hello";
console.log(propertyNameList(arr).join()); // "0"
//無理やり10のindexに突っ込むと
arr[10] = "hello";
console.log(propertyNameList(arr).join()); // "0,10"
//えっ!
console.log(arr.length); // 11
arr.shift();
//ええっ!
console.log(arr.length); // 10
ほんと、やめてください。
10. function xxxx() と var xxx = function(){} の違い
似ているからと言って同じだと思っていると痛い目を見るやつ。
xx1(); //問題なし(function xx1()は先に読まれる
xx2(); //error(xx2 is not a function)
function xx1(){
alert('go1');
}
var xx2 = function(){
alert('go2');
}
まぁ、そもそも先に未定義functionをcallするというのは避けるとは思いますが、既存コードの改修などの時にやってしまった。少しの間、何が問題か見つけられずハマった。
参考記事:
http://d.hatena.ne.jp/sandai/20100427/p1
http://steps.dodgson.org/bn/2006/04/02/
JavaScriptはクセ者です、というお話でした。