[EffectiveJavaScript輪読会]型が異なるときに==を使わない

GAS

どうも。つじけ(tsujikenzo)です。このシリーズでは2021年8月からスタートしました「ノンプロ研EffectiveJavaScript輪読会」についてお送りします。今日は第6回目です。

前回のおさらい

前回は、「オブジェクトラッパーよりもプリミティブが好ましい」をお届けしました。

[EffectiveJavaScript輪読会]オブジェクトラッパーよりもプリミティブが好ましい
どうも。つじけ(tsujikenzo)です。このシリーズでは2021年8月からスタートしました「ノンプロ研EffectiveJavaScript輪読会」についてお送りします。今日は第5回目です。前回のおさらい前回は、「暗黙の型変換に...

今回は、「型が異なるときに==を使わない」 をお届けします。

テキスト第1章「JavaScriptに慣れ親もう」の項目5に対応しています。

今日のアジェンダ

  • 強制とコーディングガイドライン
  • リーダブル厳密等価演算子
  • 等価演算子の強制ルール

強制とコーディングガイドライン

項目3で、「暗黙の型変換に注意しよう」をお届けしました。

JavaScriptでは、期待される型に合わせ、内部的に値を変換することを 「強制(Coercion)」 と呼びます。

項目3では、さまざまな強制と注意事項をまとめましたが、「では、どの書き方が正解なのか」 には触れませんでした。

項目4でプリミティブ値の生成にも触れましたし、ここらで 文字列型と数値型のコーディングガイドライン を考えてみましょう。

リテラルのコーディングガイドライン

まず、「リテラルが用意されている型は、リテラルを使う」 というルールは有益です。

new演算子が用意されているオブジェクトであろうと、リテラルを優先し、new演算子は禁止としてよいでしょう。

function myFunction1_5_01() {

//リテラルが用意されているオブジェクトはリテラルで書く
console.log(new String('Tom')); //{ '0': 'T', '1': 'o', '2': 'm' }
console.log('Tom'); //Tom

console.log(new Number(10)); //{}
console.log(10); //10

console.log(new Boolean(true)); //{}
console.log(true); //true

console.log(new Array(1, 2, 3)); //[ 1, 2, 3 ]
console.log([1, 2, 3]); //[ 1, 2, 3 ]

console.log(new Object()); //{}
console.log({}); //{}

console.log(new RegExp('.*?')); ///.*?/
console.log(/.*?/); ///.*?/

}

変換と強制のコーディングガイドライン

暗黙的に行われる型変換は「強制」ですが、プログラマが型の変換していることを、コードで明示的に示した方がいいばあいもあるでしょう。

普段、なんとなく使えているtoString()メソッドや、parseInt()メソッドも例に挙げてみました。

Myコーディングガイドラインを作成することで書き方を統一し、リーダブルコードを心がけましょう。

function myFunction1_5_02() {

//数値型から文字列型への変換と強制
const num = 10;

//好ましくない書き方
console.log(new String(num)); //{ '0': '1', '1': '0' }
console.log(num + ''); //'10'
console.log(num.toString()); //'10'

//好ましい書き方
console.log(String(num)); //'10'

//文字列型から数値への変換と強制
const text = '10';

//好ましくない書き方
console.log(new Number(text)); //{}
console.log(+text); //10
console.log(parseInt(text)); //10

//好ましい書き方
console.log(parseInt(text, 10)); //10
console.log(Number(text)); //10

}

リーダブル厳密等価演算子

JavaScriptでは、値だけでなく、型の判定まで比較する、厳密等価演算子(===)が提供されています。

Dataオブジェクトから取得した月日(数値型)と、JSON(文字列型)を比べるばあいなどは、型を揃えてから厳密等価演算子で比較しましょう。

厳密等価演算子であれば、コードを読む人が、余計な不安を抱えることがありません。「コードが増える」と言っても、たった2行です。

「処理をする」ことよりも「読まれる」ことを優先した(ただしく処理が行われることは当然です)、まさにリーダブルコードだと思います。

function myFunction1_5_03() {

const json = `{
"birthday_year": "1980",
"birthday_month": "08",
"birthday_day": "12"
}`;

const today = new Date();
const month = today.getMonth() + 1;
const day = today.getDate();

const jsonObject = JSON.parse(json);
const usersBirthdayMonth = jsonObject.birthday_month;
const usersBirthdayDay = jsonObject.birthday_day;

//厳密等価演算子では処理できない
if (month === usersBirthdayMonth && day === usersBirthdayDay) {
console.log('HappyBirthDay!!!');
} else {
console.log('今日は誕生日ではありません。'); //今日は誕生日ではありません。
}

//等価演算子なら正しい判定を行う
if (month == usersBirthdayMonth && day == usersBirthdayDay) {
console.log('HappyBirthDay!!!'); // 'HappyBirthDay!!!'
} else {
console.log('今日は誕生日ではありません。');
}

//型をそろえて、厳密等価演算子で記述しよう
const userBDMonth = Number(usersBirthdayMonth);
const uesrBDDay = Number(usersBirthdayDay);

if (month === userBDMonth && day === uesrBDDay) {
console.log('HappyBirthDay!!!'); // 'HappyBirthDay!!!'
} else {
console.log('今日は誕生日ではありません。');
}

}

等価演算子の強制ルール

ここまで強く、厳密等価演算子で書くことを推奨するのは、等価演算子を使用したさいの強制ルールが不明瞭 だからです。

valueOf()とtoString()メソッドが両方定義されているオブジェクトでは、暗黙の型変換のさい、valueOf()メソッドを優先的に呼び出し ていました。(テキストP13)

では、if(’10’ == new Number(’10’)){} というステートメントでは、数値型と文字列型のどちらで判定するのでしょうか。

正解は、「数値型」です。

テキストでは、Dateオブジェクトを例に、「等価演算子の強制により型がどうなっているかを、コードを読む人の負担にすべきではない」 と言っています。

function myFunction1_5_04() {

//オブジェクトに定義されている2つのメソッド
console.log(new Number('10').valueOf()); //10 number
console.log(new Number('10').toString()); //'10' string

//等価演算子の型強制
if ('10' == new Number('10')) console.log('両辺とも数値型に強制され比較される');

//等価演算子の強制ルール
if (null == undefined) console.log('強制はなし。常にtruthy');

if (null || undefined == !null && !undefined) {
} else {
console.log('強制はなし。常にfalsy');
}

//Dateオブジェクトはプリミティブに強制される
console.log(new Date('2021/8/12').toString());//Thu Aug 12 2021 00:00:00 GMT+0900 (Japan Standard Time)
console.log(new Date('2021/8/12').valueOf()); //1628694000000

if ('1628694000000' == new Date('2021/8/12')) console.log('今日の天気は?');
if ('1628694000000' == new Date('2021/8/12').valueOf()) console.log('今日はいい天気ですね');

}

Dateオブジェクトであれなんであれ、オペランドを比較するさいは、型を揃えて厳密等価演算子で評価しましょう、というお話でした。

※今回は、実践的な内容が多かったので、「実務を意識するなら」はおやすみしますzzz

まとめ

以上で、「型が異なるときに==を使わない」をお届けしました。

条件式では積極的に===を使い、できるだけ==を使わないように注意してきたわたしですが、「==で判定できないときは明示的に型を変換しよう」 というのは新たな発見でした。

次回は、「セミコロン挿入の限度を学ぼう」 をお届けします。

参考資料

javascript-style-guide

このシリーズの目次

[EffectiveJavaScript輪読会]ノンプロ研EffectiveJavaScript輪読会とは
[EffectiveJavaScript輪読会]どのJavaScriptをつかっているのかを意識しよう
[EffectiveJavaScript輪読会]JavaScriptの浮動小数点を理解しよう
[EffectiveJavaScript輪読会]暗黙の型変換に注意しよう
[EffectiveJavaScript輪読会]オブジェクトラッパーよりもプリミティブが好ましい
[EffectiveJavaScript輪読会]型が異なるときに==を使わない
[EffectiveJavaScript輪読会]セミコロン挿入の限度を学ぼう
[EffectiveJavaScript輪読会]文字列は16ビットの符号単位を並べたシーケンスとして考えよう

タイトルとURLをコピーしました