JavaScriptの意外な挙動

Pocket

プログラムを書いているとよくエラーが起きます。
エラーが起きないように修正していくことでプログラムが完成します。
困るのはエラーが起きないのに意図通りに動かない場合です。これは原因を探るのが難しいです。
もっと困るのは「このように動くはずだ」と思い込んでいる場合です。
JavaScriptには、このような「仕様」がいくつかあります。初心者が陥りそうなケースを挙げてみます。

parseIntの引数を省略する

文字列を整数に変換するときに「parseInt」を使います。
「parseInt(文字列,基数)」のように使い、基数に指定した進数で変換します。例えば「16」を指定すると16進数になります。
基数を省略すると10進数になりますが、恐ろしいことに文字列の先頭が「0」(ゼロ)のときは8進数になります。

a = "010";
alert(parseInt(a));

この場合、先頭が「0」なので「10」を8進数で解釈するので「8」に変換されます。「15」ならば「13」になります。必ず基数を指定して「parseInt(a, 10)」のようにするのが確実なようです。

2013年8月4日追記
コメントをいただきました。ECMAScript5で8進数としての解釈を許す表現が仕様から削除されたそうです。
parseInt - JavaScript | MDN

2022年2月4日追記
parseInt(0.0000005) が 5 になるケースがあります。途中で 5e-7 に変換されるからだそうです。
Math.trunc を使うとよいです。

文字列にプラスを付けて整数にする

数を表す文字列の前に「+」(プラス)を付けると数値に変換されます。
しかし注意しないと数値に変換されません。

a = "015";
b = "013";
alert(+a+b);

「28」になることが期待されますが、実際は「15013」になります。
「+a」で「15」という数値に変換されたものの「15+"013"」となってまた文字列に戻ってしまうのでしょう。
「alert(+a + +b)」または「alert(+ a + + b)」のように、間に加算のための「+」が必要です。見にくいので誤りの原因になりそうです。
このように計算式で使うときは一度、変数に代入するか、「parseInt」を使うのが無難でしょう。

配列の要素をlengthで数える

配列の要素を数える場合には「length」を使いますが、実際に数えているわけではありません。

x = [];
x[0] = 12;
x[2] = 13;
alert(x.length);

添え字が0の場合と2の場合だけ代入したのだから「2」になることが期待されますが、実際は「3」になります。
添え字が数字のときは最大の数字の次の数が返ります。

x = [];
x["dog"] = 14;
alert(x.length);

添え字が文字列の場合は「0」になります。

sortの比較関数を省略する

配列をソートする場合は「sort」を使いますが、比較関数を与えない場合は、数値ではなく文字列としてソートしてしまいます。

var x;
x = [10, 8, 6, 12];
x.sort();
alert(x);

「10,8,6,12」をソートするのだから「6,8,10,12」となることが期待されますが、実際は「10,12,6,8」になります。
1桁目の「1,8,6,1」を比較し、次に2桁目を比較するという「辞書的」なソートになります。
数値として昇順にソートするには比較関数として
a>bならば0より大きい値
a==bならば0
a<bならば0より小さい値
を返す関数を指定します。降順はこの逆です。
単なる数値の比較ならば
a-b
を返せばよいでしょう。

var x;
x = [10, 8, 6, 12];
x.sort(function(a, b){
  return a - b;
});
alert(x);

配列変数を別の変数に代入する

ある配列変数があって、例えば、これをソートしたいけれど元の配列も残したい、というようなケースがあったとします。
そこで、元の配列変数を新しい配列変数に代入します。
新しい配列変数をソートしたり加工したりしても、元の配列変数は変わらないことが期待されますが、実際は新しい配列変数と同じになります。

var x, y;
x = [1, 3, 4, 2];
y = x;
y.sort();
alert(x);
alert(y);

この場合、xもyも「1,2,3,4」になります。
直接、代入するのではなく、「slice」を使うとよいです。

var x, y;
x = [1, 3, 4, 2];
y = x.slice();
y.sort();
alert(x);
alert(y);

xは「1,3,4,2」のままですが、yは「1,2,3,4」になります。

[ 2013年8月3日 | カテゴリー: JavaScript | タグ: ]

« | »

コメント

  1. MOSA より:

    parseIntはES5で8進数リテラルを解釈しないようになりました
    もう心配はいりません
    また、ES6で新しい8進数リテラルが定義されました

  2. stabucky より:

    >MOSAさん
    ご指摘、ありがとうございます。
    以前、実際にこれにはまって困ったことがありましたので、例として挙げました。以来、第2引数をセットするように注意していたのですが、今、Chromeで試したら第2引数を省略しても意図通り解釈しました。仕様としてはこちらの方がいいですね。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

送信してください。


タグ

カテゴリー

最近の投稿

最近のコメント

固定ページ

アーカイブ

stabucky

写真

メタ情報