ワテの場合、JavaScriptを勉強し始めて約一年経った。
JavaScriptはその名の通りスクリプト言語なので、コンパイル言語に比べていろいろとヘンテコな事が出来る。
ヘンテコな事が大好きなワテにはJavaScriptはとっても使い易い言語だ。
数字も文字列もミックスして演算するなども可能だ。
それは便利ではあるけれど、場合によっては変数の中身がどんな値が入っているのか知りたくなる場合もある。
この記事では、JavaScriptプログラミングにおいて与えられた変数の中身が
- 整数
- 整数文字列
- 実数
- 実数文字列
のどれなのかを判定する関数を作ってみた。
結論としては、何かの役に立つかもしれない。
また、ワテ自身のJavaScriptの変数型の理解が深まった。
では、本題に入ろう。
JavaScriptの変数型を理解する
JavaScriptでは変数はvar宣言して使う。
'use strict'; // これがあるとvar宣言が必須となる。 var a = 12345; // 整数を代入したあとで、 a= 123.45; // 実数を代入しても良いし、 a='123.45'; // 文字列を代入しても良い。
var宣言しなくていきなり使っても良いのだが、変数宣言くらいはしておくほうが安全だ。
Visual Studio 2015のデバッガで見るとこれらの変数は、
Number 整数、実数どちらでもNumber型
String 文字列
の型で格納される。
JavaScriptの数値型には、C#, C/C++ のような integer, float, double といった区別は無い。
またC#なら一文字はchar型、文字列は string型になるが、JavaScriptにはそういう区別は無くて、全部String型として扱える。
JavaScriptはシンプルで分かり易いから、ワテ好みの文法だ。
ちなみにJavaScriptには、
Object オブジェクト型
と言うのもある。
C#などの Dictionary<Key,Value> のように使える。
いわゆる連想配列と言う奴だ。
var dic_csharp = new Dictionary<string, string>(){ { "cat", "猫" }, { "red cat", "赤猫" }, // そんな猫おるんか? { "black cat", "黒猫" }, };
これをJavaScriptで書くと、
var obj_JS = { cat: '猫', dog: '黄猫', 'black cat': '黒猫', // Keyに空白が入る場合は' 'で囲って文字列化必要 };
こんな感じか。
重複するKeyは登録出来ないので、例えばKeyにcatが二回出て来るとエラーする。
一方、C#でもJavaScriptでも、Keyに対してValueを取り出す操作は、
C#
var neko= dic_csharp["cat"]; // 文字列 "猫" が得られる。
JS
var neko = obj_JS['cat']; // 文字列 '猫' が得られる。 var neko = obj_JS.cat; // こういう形式でも良い。
となる。
ちなみに、JavaScriptでは
シングルクオーテーション ’
ダブルクオーテーション “
のどちらで囲っても文字列となる。全く同じ役割だ。
ワテはシングル派なので ‘文字列 ‘ の形式を良く使う。
見た目がすっきりしているからだ。
さて、
JavaScriptをやっているとNumber型もString型も意識しなくても良い
例えば、
var a = 100; // Numberで a を宣言していても、 console.log('varの値は=' + a ); // 文字列として出力
とすると、文字列と数値aが上手い具合に連結されて文字列として出力出来る。
逆に、
var a = '100'; // Stringで a を宣言していても、 a = a/2; // この計算結果をaに代入した時点で Number型に変わり、 console.log('a='+a); // a=50 と表示される。
このヘンテコ度合がワテは好きだ。
他のスクリプト言語でもこういう仕様のものは多いと思う。
JavaScriptでプログラミングをしている場合には、こんなふうに、変数型を全く意識しなくてもプログラムは書けるので便利だ。
でも、状況によっては、与えられたデータが
- 数値としての整数
- 数値としての実数
- 文字列としての整数
- 文字列としての実数
のどれなのか知りたいという場合も時々ある。
例えばGoogle Maps API を使って地図アプリを作成している場合だと、(緯度, 経度) の値を良く使う。
33.5905576, 130.4217855
こんな感じ。
これが文字列で何らかの変数に入っているとして、緯度と経度を個別に取り出すなら、
var latlng_str = '33.5905576, 130.4217855'; var latlng_ary = latlng_str.split(','); var lat = latlng_ary[0]; // '33.5905576' var lng = latlng_ary[1]; // '130.4217855';
こういう感じか。
この時点でもまだ文字列なので、もし数値化したいなら、
var lat_dbl = parseFloat(lat); // Numberの33.5905576 実数化 var lng_dbl = parseFloat(lng); // Numberの130.4217855 実数化 var lat_int = parseInt(lat, 10); // Numberの33 整数化 var lng_int = parseInt(lng, 10); // Numberの130 整数化 var hex = parseInt('FFFF', 16); // 文字列を16進として扱い10進化➜65535になる
こんな感じか。
parseInt() 切り捨て
Math.round() 四捨五入
なので使い分けが必要だ。
parseInt()の問題点
parseInt, parseFloatは便利なのでワテのプログラム中でも使いまくっているのだが、問題がある。
それは、
var a = parseInt('12wareko', 10); // 12になる var b = parseInt('x12wareko', 10); // NaNになる
のように、文字列自身が正しい数値を表していなくても、先頭に数値に変換出来る部分文字列が有る場合には、数値に変換してしまうのだ。
確かにこの挙動は便利な場合もある。
良く遭遇する場面は、DOMの要素の例えば<div></div>の幅や高さをjQueryで取得すると、
‘300px’
のようにピクセル単位を表す ‘px’ が付いた形式で得られる場合がある。
その300pxに100pxを加算して幅を400pxに広げたい場合には、
var wid_new = parseInt('300px', 10) + 100; // = 400 となる $('#div_ID').width(wid_new); // width(400)で幅が400pxに広がる $('#div_ID').width('400px'); // これでも良い document.getElementById('div_ID').style.width = '400px'; // これもOK document.getElementById('div_ID').style.width = '400'; // これは効かない
こんな感じか。
とても便利なのでparseIntを使いまくるのだが、JavaScriptで文字列や数値を意識せずにプログラムを書いていると、
var c = '12' + b; // b=NaN, c='12NaN' こんな予想外の文字列であっても、 var d = parseInt(c, 10); // 気付かずに整数化すると、数値 12 が得られる。
parseInt, parseFloatは便利な反面、こういうよけいなお世話な感じの挙動がワテには困る。
ワテならこういう場合には数値には変換出来ない仕様にするな。
つまり、文字列として完全な数値を表している場合のみ、parseInt()変換を行う。
不正な文字列なら数値には変換せずにNaNを返す。
そういう手法を実現する方法がないか少し検索してみたのだが、見付けられなかったので自分で作ってみた。
データが整数、実数、整数文字列、実数文字列なのか判定する関数(ワテ流)
即席で作ってみた。
'use strict'; function isIntNum(value) { // 整数判定関数2 // MDNのを使ってみる。 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger return typeof value === "number" && isFinite(value) && Math.floor(value) === value; } function isFloatNum(n) { // float数値判定 stackoverflowで見つけた奴。まあいい感じ。 // How do I check that a number is float or integer? // http://stackoverflow.com/questions/3885817/how-do-i-check-that-a-number-is-float-or-integer return n === Number(n) && n % 1 !== 0; } function isIntStr(s) { // 整数文字列判定関数 if (typeof s === 'string') { if (isNumericJQ(s)) { var n = parseFloat(s); return isIntNum(n); } else { return false; } } else { return false; } } function isFloatStr(s) { // 実数文字列判定関数 if (typeof s === 'string') { if (isNumericJQ(s)) { // s='123.456=' var n = parseFloat(s); // もし↑が無いと←は '123.456' となり return isFloatNum(n); // ここで true と判定され、結局、'123.456=' がfloat strに誤認する問題があるから。 } else { return false; } } else { return false; } } function isNumericJQ(any_data) { // jQueryの数値判定関数 var rc = jQuery.isNumeric(any_data); return rc; }
動作実験
テキストボックスの文字列を適当に変更すると、判定結果が再計算されます。
大体動いたのだが、一部問題がある。
123.000 '123.000'
のどちらも整数と判定してしまう。
理由は、上記の関数内の処理を見て頂くとだいたいお分かり頂けると思うが、整数の判定を
Math.floor(value) === value;
という単純な比較で行っているので、
123.000 === 123
はtrueになり123.000は整数と判定される。
う~ん、まあいいか。
もし厳密に判定するなら、正規表現を使うなどで改良すれば良いか。
まとめ
JavaScriptでデータが整数、実数、整数文字列、実数文字列なのか判定する関数を作ってみた。
いちおういい感じで動くので何かの役に立つかもしれない。
即席で作ったのでヘンテコ部分も多い。
もっと洗練された手法がありましたら教えて下さい。
JavaScript・jQuery関連本を読む
JavaScript、jQueryなどに限らず、プログラミング言語を勉強しようと思っている人は一冊本を読み通す事が重要だ。
その言語に、
どういう関数があるのか
どういう文法が使えるのか、
など、基本的な事を頭に入れておくと良い。
もしそれを怠ると、自己流でヘンテコな関数を作ってしまうなどの無駄がある。
そんな関数を作らなくても、jQueryの関数があるやんと言う感じ。
ワテも、jQuery版の数値判定関数
jQuery.isNumeric(arg)
の存在を知らなかったので、危うく自作を試みる所だった。
コメント