LoginSignup
28
12

More than 3 years have passed since last update.

バグを引き起こしかねないJavaScriptの仕様

Last updated at Posted at 2019-12-01

はじめに

はじめまして。advent calendar初参戦の中村です!
ZealsにはRailsエンジニアとしてJoinしましたが、3ヶ月ほど前からReactをメインに書いています。
Reactの勉強と並行して一ヶ月ほどJavaScriptの勉強も行いました。
その際に『気をつけないとバグに繋がるな〜』と思った仕様について書いていこうと思います!!

+演算子

JavaScriptには数値の足し算と文字列連結の『+』があります。
以下のコードがどのような挙動になるか是非一度考えてみてください!


console.log(3 + 4 + '5');
console.log('3' + 4 + 5);

結果は

 '75'
 '345'

となります。

なぜか

JavaScriptの『+』はこのように処理されます。

  • JavaScriptの処理は被演算子のデータ型から『+』が加算なのか、文字列連結なのかを判断する。
  • 加算と文字列連結はいずれも左から右に評価される。

➀はまず(3 + 4)が加算として評価され、次に(7 + '8')が文字列連結として評価されます。
➁は('3' + 4)が文字列連結として評価され、次に('34' + '5')も文字列連結と評価されます。
ちょっと不思議な挙動ですよね。。。

+演算子は挙動がわかりづらいので、

`${4 + 5}`

こんな感じに書いたらわかりやすいかもしれません!

おまけ

面白かったので、色々試してみると

true + 1
> 2

false + false
> 0

1 + 'test'
>"1test"

'test' + false
> "testfalse"

3 + +'3'
> 6

といった感じになります。。。笑

NaNとisNaNとNumber.isNaN

NaNは、Not a Numberの頭文字をとった特殊な値です。
なるほど。。。どうやらNot a Numberから推測するに数値ではなさそうですね!
ただ、typeof演算子を使ってみると。。。

console.log(typeof NaN)
> 'number'

number!?!?!?
『Not a Number』とは一体。。。

その他にもNaNにはNaN自身を含め、どの値とも等しくならないという特徴があります!

NaN === NaN //false

そのため、NaNかどうかを確認するためには組み込み関数のisNaN()を使います!
以下のコードがどのような挙動になるか是非一度考えてみてください!


console.log(isNaN(1));
console.log(isNaN("1")
console.log(isNaN(Infinity));
console.log(isNaN(null));
console.log(isNaN("9"));
console.log(isNaN(true));
console.log(isNaN(false));
console.log(isNaN(NaN));
console.log(isNaN(undefined));
console.log(isNaN("1yen"));

結果は

console.log(isNaN(1)); //false
console.log(isNaN("1")); //false
console.log(isNaN(Infinity)); //false
console.log(isNaN(null)); //false
console.log(isNaN("")); //false
console.log(isNaN(true)); //false
console.log(isNaN(false)); //false
console.log(isNaN(NaN)); //true
console.log(isNaN(undefined)); //true
console.log(isNaN("1yen")); //true

となります。
NaN以外もtrueが返ってきているような気がします。。。

なぜか

isNaN関数の引数が数値型ではない場合、その値はまず数へと型を矯正されます。その後NaNかどうかがテストされます。
数値型に型を強制される際に結果がNaNではない数値となる非数値(とりわけ型強制されると0や1の値になる空文字列や真偽値プリミティブ)に対しては、falseが返されるといった事になります。

ちなみに

es6以降からNumber.isNaN関数が追加されました!
グローバルのisNaN()関数とは異なり、Number.isNaN()は強制的に引数が数値に変換されません。この関数は、数値型であり、かつ NaNである値が渡されたときのみ、trueを返すということです。

Number.isNaN(NaN);        // true
Number.isNaN(Number.NaN); // true
Number.isNaN(0/0)       // true

//以下全てfalse
Number.isNaN(undefined);
Number.isNaN({});
Number.isNaN(true);
Number.isNaN(null);
Number.isNaN(1);
Number.isNaN('1');
Number.isNaN('1.1');
Number.isNaN('');
Number.isNaN(' ');
Number.isNaN('NaN');
Number.isNaN('test'); 

isNaNとNumber.isNaNの挙動の違いとかもしっかり押さえておきたいですね!

nullとundefined

JavaScriptにはnullundefinedといった二つの特殊な型があります。
nullが取る値はnullのみで、undefinedも同様です。
「null」は空っぽで「undefined」は未定義であることを意味しています。

let x; //undefined
let y = null; //null

変数「x」は値が何も格納されてない、何も定義されてないのでundefinedになります。
変数「y」には値として「null」が定義されているので、この変数の中身は空っぽであることが明示されています。

「==(等価演算子)」と、「===(厳密等価演算子)」でnullとundefined確認してみましょう!!

console.log(null == undefined)
> true
console.log(null === undefined)
> false

このことから、値は同じですが、型が違うことが推測されます!!

そこでtypeof演算子でnullとundefinedを確認してみます!

undeifined
console.log(typeof undefined)
> 'undefined'

想定通り'undefined'が返ってきました!

次にnullを確認して見ましょう!

null
console.log(typeof null)
> object

object!?!?!?
確かにnullとundefinedの型が違うことは確認できましたが、nullがobjectであるという、別の疑問が生まれました。。。
これは混乱しますね。。。

nullが何故このような仕様になっているかというと、『過去にこのように使われていたから』といった理由だけだそうです!
この仕様を変えるべきだという提案が度々されていますが、あまりにも多くの既存コードがこの動作に依存しているため、未だにこの言語仕様が残っているそうです。。。

これは仕方が無いと受け入れるしかなさそうですね。。。

その他

その他にもちょっと気になった事があったのでサクッと紹介します!!

日付処理の月が0から11

let date = new Date()
 > 2019-12-01T18:17:08.862Z
date.getMonth(); // 11

何でや。。。

オブジェクトのlength

let obj = {a:"a",b:"b"};
obj.length
> undefined

rubyだと2を返してくれるのですが、JavaScriptだと一手間必要です!


Object.keys(obj).length
> 2

不親切な気がしないでも無いです。。。

空文字と空配列と空オブジェクトの真偽値

空文字("")と空配列([])と空オブジェクト({})の真偽値は以下のようになります

Boolean("")
> false
Boolean([])
> true
Boolean({})
> true

空文字のみfalseと判定されます。

終わりに

上記で述べてきたJavaScriptの仕様を、しっかりと抑えておきたいですね!(バグに繋がりそうなので。。。)
ここまで色々書いてきましたが、僕はJavaScriptが大好きなので、これからもJavaScriptを書き続けようと思っています!
それではここら辺で、明日の@suzuki-marさんに繋ごうと思います!
最後まで読んで頂きありがとうございました!

参考文献

初めてのJavaScript 第3版―ES2015以降の最新ウェブ開発

28
12
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
28
12