質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

4回答

2054閲覧

条件文で「"" < 1」がtrueになる理由が分からない

yufane

総合スコア13

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

1グッド

0クリップ

投稿2019/03/11 04:39

質問

JavaScript

1if (temperature < 25 && temperature > -5) { 2 -処理- 3}

temperatureに数値を代入したら何の問題なく判定してくれます。しかし、空文字""を入れたときも処理が実行されてしまいます。もちろんtemperatureには数値だけしか代入できないようにすればそれで良いのですが、次の事実が成り立ってしまうのがどうしてなのか分かりません。

JavaScript

1"" < 25 && "" > -5 //true

試したこと

JavaScript

1"" < 1 && "" > -1 //true 2"" <= 1 && '' >= -1 //true 3"" > 1 || "" < -1 //false 4"" >= 1 || "" <= -1 //false

-1 < "" < 1なので、空文字は0なのか試してみると

JavaScript

1"" == 0 //true 2"" === 0 // false

という結果になりました。
つまり大小比較の関係演算子は暗黙の型変換をしているということになるのでしょうか?
もしそうであれば型変換を回避する良い方法を教えていただけると幸いです。

bochan2👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

大小比較の関係演算子は暗黙の型変換をしているということになるのでしょうか?

はい。比較演算を行う場合、両者はToPrimitiveという操作で変換され、さらにToPrimitiveの結果が「両方文字列」の場合は文字列比較、そうでない場合は数値比較となります(ES2019)。

"" < 25の場合、もとからプリミティブなので文字列と数値の比較になり、空文字列が数値に変換されて0となり、それとの比較になります。

投稿2019/03/11 04:54

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2019/03/11 05:00 編集

なお、ToPrimitiveをオブジェクトに適用した場合、ES6以上の環境でobj[Symbol.toPrimitive]が定義してあればその結果に、それがなければ.toString()や.valueOf()を使って変換します。 https://qiita.com/uhyo/items/44c2f79873de13186743
yufane

2019/03/11 05:06

詳しいことを教えていただきありがとうございます。
guest

0

JavaScriptのエンジン部分はブラウザ作ってる各社が勝手に実装しているのですが、
「ECMA TC39 委員会」という団体のECMAScriptで厳密な挙動の仕様が明記されており、
ECMAScriptを読めば型変換等のルールも明記してあるので探せば出てくるはずです。

しかし面倒くさいのでMDNの中で探します。
関係演算子セクション - MDN

これらの演算子はそれぞれ、比較前に各オペランドに対して valueOf() 関数を呼び出します。

JavaScript

1console.log(("").valueOf()); // "" 2console.log((5).valueOf()); // 5

はーつっかえ
まぁ、特殊なクラスのインスタンス同士でも、
valueOfメソッドを用意して絶対的な数値に変換出来るのであれば関係演算子で比較出来るよという趣旨の事が書いてあります。


しょうがないのでECMAScriptの仕様書を見に行きます。
11.8.5 The Abstract Relational Comparison Algorithm

If it is not the case that both Type(px) is String and Type(py) is String, then

Let nx be the result of calling ToNumber(px). Because px and py are primitive values evaluation order is not important.

Google翻訳使いながらの斜め読みですが、
どうやら比較対象がStringならばToNumberを行って比較するというルールになっているようです。
ToNumberとはなんぞや?

これはMDNに記述されていました。
== による緩い等価性 - MDN

この記述自体は==のものですが、String型はToNumberを行うものとする。
ここでもToNumberが出てきました。
そして、そのロジックは(+値)としたものと同様です。

JavaScript

1console.log(+""); // 0 2console.log(+"10"); // 10 3console.log(+"one"); // NaN 4console.log(+"10month"); // NaN

というわけで、比較演算子に""が紛れ込んだ場合、数値の0として取り扱われます。

型変換を回避する良い方法を教えていただけると幸いです。

比較演算子は型変換を回避する方法はありません。
なので、そもそもそれが数値型ではなかった場合に処理を中断するようなコードの組み方にしましょう。

質問文のコードに応急手当てをするとこんな感じになるでしょう。

JavaScript

1if (typeof temperature === "number" && temperature < 25 && temperature > -5) { 2 // -処理- 3}

ただし、どう見ても数値の範囲絞り込みを行っている箇所なのに、
何故か空文字が混入してしまい、空文字と数値を比較し始めている時点でクソコードです。
なので源流の方を修正して、綺麗にフィルタリングしてせき止めるようにすることを推奨します。

投稿2019/03/11 05:18

編集2019/03/11 15:11
miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

think49

2019/03/11 12:26

> W3Cという団体が出しているECMAScriptのサイトに厳密な挙動の仕様が明記されており、 Ecma International の認識でしたが、元を辿れば、W3Cだったりするのでしょうか。 https://www.ecma-international.org/
miyabi-sun

2019/03/11 15:09

あら、W3Cから派生したと思ってましたが私の完全な勘違いですね。 W3CはあくまでDOM APIの仕様策定に携わっただけで全く携わってはいませんでした。 http://www.madmode.com/2013/js-w3c-ecma.html ECMAScriptを作っているのは「ECMA TC39 委員会」でW3Cとは関係無いのですね。 本文を修正しておきます。
guest

0

数値同士、文字列同士の比較ではなく型が違うものの比較ですから
適当なキャストをして比較します

javascript

1console.log(2>10); // false 2console.log("2">"10"); //true 3console.log(2>"10"); // false 4console.log("2">10); // false

追記

こうすると両辺が数値にキャストされていることがわかりやすいと思います

javascript

1console.log("1e2"<2); // false 2console.log(2>"1e2"); // false 3/* 右辺にあっても左辺にあっても1e2は10にキャストされるのでfalse */ 4console.log("1e2"<"2"); // true

投稿2019/03/11 04:53

編集2019/03/11 05:07
yambejp

総合スコア114814

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yufane

2019/03/11 05:10

分かりやすい解説ありがとうございます
guest

0

js

1"" == 0 //true 2"" === 0 // false

intとstringの比較になってるし
下にしたい場合はしっかりと型を合わせないと無理だよ。
parseIntを使って試してみて。

投稿2019/03/11 04:45

編集2019/03/11 04:46
stdio

総合スコア3307

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

miyabi-sun

2019/03/11 04:52 編集

今回の質問は知的好奇心からのECMAScriptの型変換ルールに対する質問です。 「実践で型が違う比較演算なんてありえないから型を合わせろ」というのは仰る通りでございますという感じなのですが、 なんでこんな仕様になっているのかという説明を入れた方が良いと思います。
stdio

2019/03/11 04:57

``` /** * https://oki2a24.com/2015/09/19/how-to-know-object-inside-in-javascript/ * オブジェクトのプロパティとその値を文字列化して連結したテキストを返却します。 * * @param {object} obj オブジェクト * @return {string} プロパティとその値を文字列化して連結したテキスト */ function getProperties(obj) { var properties = ''; for (var prop in obj){ if(prop == null || !obj[prop]) continue; properties += prop + ': ' + obj[prop] + '\n'; } return properties; } ``` この関数使って型でも調べてなさい。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問