JavaScriptの配列の反復処理にfor..in文を使うとインデックスが文字列型になる

Facebook にシェア
Pocket

気づいたら元号が変わってました。アウトプットが大事と書かれている本を読んでインプットしながら、アウトプットしない日々を送っています。

先日、仕事で配列の探索をしようと、下記のような処理をしました(実際にはもう少し複雑です)。

やっていることは単純に、配列からある’バナナ’という文字列が入っているインデックスを取得し、インデックスが1だった場合に、コンソールに’バナナは2つ目です’と出力しているだけです(これぐらいならArray.prototype.indexOf() – JavaScript | MDNを使えよと思われそうですが、実際にはもう少しループの中で複雑なことをしていました)。

一見、普通に’バナナは2つ目です’と出力されるような気がしますが、何も出力されません。見つからなかったら、’バナナはみつかりませんでした’と出力されるはずですが、それすらでてきません。

おかしいなぁ。と思って試しに、「i === 1」を「i == 1」としてみると、なんと’バナナは2つ目です’と出力されました。もしかしてと思って、最後に「console.log(typeof pos)」といれると、stringと出力されました。

配列のインデックスを「arr[‘0’]」というように、数値の文字列型で取得できるのは知ってたのですが、for..inを配列で使うと、インデックスは文字列型になってしまうことは知りませんでした。まあ、確かにfor..inはあくまでオブジェクトのプロパティ名が代入される処理ですしね。

MDNを見ると、「注: for…in はインデックスの順序が重要となる 配列 の繰り返しには使うぺきではありません。」と書かれてました(参考:for…in – JavaScript | MDN)。普通のforループかforEachを使うのがよさそうです。

ただ、forループだといちいちlengthの指定が必要だし、forEachだと途中で抜けれなくて無駄な処理が多くなりそうなので、for…inにしました。ですが、もう少し調べてみると、Array​.prototype​.some()を使うと自分のやりたいことはできそうだと発覚。

Array​.prototype​.some()ってあまり使う機会ないと思って使ったことなかったんですけど、こういう使い方もあるなら結構いろいろ使いどころありそうです。

jquery.ajaxに代わる、Fetch APIについて

Facebook にシェア
Pocket

最近のJavaScriptでは、jQueryに依存しない書き方が増えてきたようです。ただ、確かにセレクターなら、document.querySelectorAllメソッドを使えばいいだけなんですが、個人的にjQueryで便利なところは、ajaxだと思ってるんです。いちいち、XMLHttpRequestがどうちゃらこうちゃらとか書きたくないし、だいいち覚えられない。だから自分は、jQueryからはなかなか離れられないだろうし、離れたとしてもAjaxようの共通関数は実装することになるんだろうなぁ。と思っていたら、最近になってFetch APIなんてものを知りました。

最近のWeb技術界隈は追えていないと思ったらこんなものが。というわけで、調べて使ってみました。

HTML

PHP

サンプル:Document

やってることは、サーバーに数値と文字列をPOSTで渡すと、数値を2倍、文字列をSHA-256でハッシュ化した結果をJSON形式で返すというもの。例えば、数値を123、文字列をabcとすると下記のようになりました。

確かに数値は2倍になって、文字列はハッシュ化して返ってきました。ちょっとよく分からなかったのが、最初にResponseオブジェクトからどういう形式で値を取得するかという指定が必要なこと。これがPromiseオブジェクトで返ってくるので、いちいちthenを二回書かなきゃいけないという。response.json()で返ってくる値がPromiseオブジェクトじゃなくて、JSONオブジェクト(多重表現)になってるほうが直感的でわかりやすい気がするのだけど、多分、こうなってるメリットはあるんだろうと思う。このへんは多分、自分がPromiseについてよく分かってないから疑問に思ってるのだと思うので、もう少しこのへんも勉強していこうと思う。

ところで最初、fetchのbody部分を「body: new FormData(document.getElementById(‘frm’))」と指定しようと思ったのですが、それだといまいちメリットがないなと思ったら、JSONで渡せることを知ったのでそうしました。PHP側で『json_decode(file_get_contents(‘php://input’), true);』とすればいいそうです。初めて知りました。JSONのまま渡せるなら、便利ですね。これからはそうしようかな。

画面内に入ったり出たりした時の処理を行う「Intersection Observer」について

Facebook にシェア
Pocket

先日、超速! Webページ速度改善ガイド ── 使いやすさは「速さ」から始まる (WEB+DB PRESS plus)という本を読んで知ったのですが、最近のWebブラウザのJavaScriptには、「Intersection Observer」というAPIがあるらしく、このAPIを使うことで画面内に入ったか(もしくは画面外に出たか)どうかを判定できるそうです。

便利そうなので、試しに使ってみました。画面に四角い要素を100個並べて、画面に入ったり出たりすることで背景色が変わるサンプルです。試しに、今まで知ってはいたけど使ったことがないCSSアニメーションや、ES6から実装されたletやconstやアロー関数も使っています。

HTML

CSS

JavaScript

サンプル:Intesection Observeテスト

スクロールしたり画面サイズを変更したりすることで、四角い要素が画面内に入ると、背景色が1秒かけて青からオレンジに変わると思います(IE以外の最新ブラウザ対応)。

ただ、すばやくスクロールしているとたまにうまく動作しないことがあるみたいです。あまりアテにしすぎるのもよくないのかも(自分がよく分かってない可能性もおおいにあります)。

なお、IntersectionObserverの第2引数にはどの要素の交差を判定するか(なければブラウザのビューポート)のrootと、ルート回りの余白を指定できるrootMargin、それと可視性がどれぐらい入ってるか出ているかでコールバックを実行するthresholdというオプションがあるそうです。
参考:Intersection Observer API – Web API インターフェイス | MDN

超速!  Webページ速度改善ガイド ── 使いやすさは「速さ」から始まる (WEB+DB PRESS plus)
佐藤 歩 泉水 翔吾
技術評論社
売り上げランキング: 11,340

JavaScriptで日時の加減算を行う

Facebook にシェア
Pocket

またもや、改訂新版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用までから。

JavaScriptの日時処理は少し面倒だという印象があります。上で紹介した本を読んでも、ES2015でもそれは変わってないらしく、例えばフォーマットによる日時を付与した関数なんてものも用意されてないらしいです。

その点ではMoment.jsというライブラリ(参考:Moment.jsを使う – Qiita)がよさげではあるのですが、今回は素のJavaScriptを使った加減算について。

というのもやり方は簡単で、DateオブジェクトのgetXxxxxメソッドとsetXxxxxメソッドを使えばいいだけだそう。実は、本をよむまで、getとつくメソッドがあるのは知ってたけど、setとつくメソッドがあるのは知らなかった。

使い方としては以下。

見て分かるように、月をまたいでもちゃんと計算される(それにしてもなぜ、月だけ0始まりにしたのだろうか。最初間違えて、『new Date(2016,11,6,22,30);』として12月6日になって混乱した)。

これを応用したら、指定の日付の月末日を取得することができる。

ちなみに、setXxxxメソッドの戻り値は、Dateオブジェクトではなくて1970 年 1 月 1 日 00:00:00 からのミリ秒数。Dateオブジェクトだったらメソッドチェーンが利用できたので少し面倒。まあ、目的は変更後の日付を返すのではなく、自分自身の日付を変更するということだから仕方ないか。

まあ、やろうと思えば下記のようにできなくはない。

いや、これはメソッドチェーンとは言わないか。

というよりよくよく考えたら、Dateオブジェクトを新しく生成すればいいだけでした(調べて気づいた)。

なお、日付通しの計算については、getTimeメソッドを利用して数値化したうえで、1単位をミリ秒数で表した数で割らなきゃいけないそうです。

なんで標準でこれぐらいの計算が簡単にできるメソッドが用意されていないのだろうか……。ES2015では追加されるんじゃないかと期待していたのだけど……。

JavaScriptで、できるかぎり小数演算の誤差を少なくする方法

Facebook にシェア
Pocket

JavaScriptにかぎらず、プログラミングでの小数を含む演算では誤差が発生してしまうことがよくあります。例えば、『0.2+0.1』という単純な足し算すら、『0.30000000000000004』という結果になってしまいます(Chromeで確認した場合)。その対応方法が改訂新版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用までに書いてあったのでメモしておきます。

対応方法といっても単純なことで、ようは小数をいったん小数の長さ分の10の累乗を掛けて整数にしてから演算し、それから10の累乗分した数を割って正しい値を取得するというもの。最後の10の累乗で割るときに誤差が発生してしまうのではないかと思いそうですが、割られる方の数が整数であれば誤差は発生しないようです(例えば、『12.35/10』の結果は『1.2349999999999999』となるけど、『1235/1000』の結果は『1.235』となる)。

というわけで、小数の演算に対応した関数を書いてみました。

足し算、引き算、掛け算、割り算の4つの関数がありますが、上半分はすべて同じです。本来ならこの部分は共通化しておいたほうがいいでしょうね。エラー処理は余計だったかもしれません(この処理がなくても、どのみち例外エラーが発生するのだし、throwで返すのではなく、0やnullを返すとかでもいいかも)。

エラー処理はまず引数が数値かどうかチェックし、その後に指数表記かどうかを調べています。

実行した結果は下記のとおりです(『//=>』より右側が実行結果)。

ところで今回、小数って英語でなんていうんだけと思って調べて、英語でdecimalということを初めて知りました。decimalというと、10進数というイメージがあるのだけど、小数という意味もあったのかと。どっちの意味で使ってるか分かりづらいことってないのだろうか。