LoginSignup
23
30

More than 5 years have passed since last update.

知らないとバグになる、JavaScriptがクセ者だと思う10の仕様

Last updated at Posted at 2018-09-21

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はクセ者です、というお話でした。

23
30
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
30