JavaScriptのnew Date()コンストラクタにはマイナスも指定可能

ソースレビュー中に驚く記述がありました。

var year = 2017;
var month = 2;
var day = 22;
var d = new Date(year, month-3, day); // 3ヶ月前

いやこれ、月がマイナスになる場合は落ちるんじゃないか、と思いました。

 

ところが、実際に動かしてみるとこうなります。

 

ちゃんと今日から3ヶ月前の日付になっていると思います。

 

Mozillaの開発者向け情報にJavaScriptのDateの仕様か記載されています。

Date - JavaScript | MDN

ほかの技術ブログなどでもそうですが、monthには0~11、dayには1~31が指定可能と記載されています。

ブラウザの実装に依存する形ではありますが、主要ブラウザではいずれも正常に動作しています。

 

以下は実際に動かしてみた各コンストラクタの内容です。思ったよりいろいろと指定できるようです。

コンストラク引数引数の例出力される内容備考
new Date() (引数無し) (引数無し) 現在の日付  
new Date(long) MilliSeconds 946652400000 1900/1/1 00:00:00から経過したミリ秒  
new Date(int) year 2013 入力した年数の1月1日(世界標準時)  
new Date(String) dateString 2017/02/22
2017/2/22
2017-02-22
2017/2/22 21:15:9
入力した文字を日付にしたもの スラッシュ(/)区切りなら1桁は0が不要
ハイフン(-)区切りなら必ず2桁必要
Date.parse()で解析できる文字列ならOK
new Date(int, int) year, month 2017, 02 入力した年数、月の1日 mmにはマイナスも指定可能。指定した場合、-1ならyyyy-1の12月
new Date(int, int, int) year, month, day 2017, 02, 22 入力した年数、月、日の00:00:00 mm、ddにはマイナスも指定可能。mmが-1ならyyyy-1の12月、ddがマイナス-1ならyyyy-1、mm-2の末日
new Date(int, int, int, int) year, month, day, hour 2017, 02, 22, 21 入力した年数、月、日のhh:00:00 hourにもマイナス指定が可能。hourがマイナスなら↑の年月日の前日23時
new Date(int, int, int, int, int) year, month, day, hour, minute 2017, 02, 22, 21 入力した年数、月、日のhour:00:00 minuteにもマイナス指定が可能。minuteがマイナスなら↑の年月日の時間から1分引いた時刻
new Date(int, int, int, int, int, int) year, month, day, hour, minute, second 2017, 02, 22, 21, 36, 29 入力した年数、月、日のhour:minute:second secondにもマイナス指定が可能。secondがマイナスなら↑の年月日の時間から1秒引いた時刻

 

jQueryでテキストエリア内のスクロールが発生しているか検知する方法

いつの間にか新年になっていました。

あけましておめでとうございます。今年もよろしくお願いします。

 

html上の要素を制御する方法について色々と調べていたら、面白そうなものを見つけました。

jQuery でサイズや位置を取得する方法を図にしてみた - Cyokodog :: Diary

jQuery必須というわけではないですが、意外と多くの情報が取れることがわかりました。

その中に、スクロールバーが存在するボックス要素内の各種height値の取り方です。

今回はわかりやすく、テキストエリア内にスクロールバーがあるかどうかを検知するスクリプトを書いてみました。

テキストエリア内のスクロールが発生しているか検知する方法

テキストエリア内に縦や横のスクロールバーがあると、バーの分だけ幅や高さが変わります。ただ、記事を読む限りではwidthheightの値はpaddingで調整されたあとの内側のサイズを返すようです。

その代わりに、clientHeightpaddingも含めた高さ、offsetHeightborderも含めた高さを取得できるようです。

さらに、scrollHeightはスクロールによって非表示になった部分も含めた高さを取得できるみたいです。

ということは、これらを比較することで要素内にスクロールバーがあるかどうかを検知することができそうです。

実際に動かしてみました。

スクロールバー:出てないよ

 

テキストエリア内で適当に長文や改行を入れてフォーカスを外すと、テキストエリア内にスクロールバーがあるかないかを表示します。

コードはこんな感じ。

$('textarea').blur(function() {
  var ch = $(this).prop('clientHeight');
  var sh = $(this).prop('scrollHeight');
  if (ch < sh) {
    // スクロールバーがあるときの処理
  } else {
    // スクロールバーがないときの処理
  }
});

テキストエリア要素のclientHeightscrollHeightを取得して比較し、scrollHeightのほうが大きい場合にスクロールバーがあると見なしています。

記事中だとattrで取得していましたが、試してみたところpropじゃないと正しく取得できませんでした。jQueryのバージョンなどが関係しているのかもしれません。

 

使い道があるかはわかりませんが、ちょっと面白いと思いました。

jQueryのtriggerでaタグのhrefへ遷移させる方法

リンクを描画するための極めてシンプルな方法として<a>タグのhrefがあります。

あずまや

<a href="http://azuma006.hatenablog.com/">あずまや</a>

 

<a></a>タグで囲まれた文字列をクリックすると、href属性に書かれたURLへ遷移します。

今回はAjaxでなんらかの処理をしたあと、画面内のリンク先へ遷移させるため、jQueryのtriggerという関数を使って、JavaScriptの処理としてマウスクリックを実現して遷移させようとしました。

<!--
$(function() { $('#submitBtn').click(function() { // なんらかのAjax処理 start
~~~ 省略 ~~~
// なんらかのAjax処理 end
    $('#back').trigger('click');
}); }); //-->
<input type="button" value="ボタン" id="submitBtn" /> <a href="/hoge/fuga" id="back">戻る</a>

なんとなく雰囲気が伝わればよいですが、ボタンを押すとAjax通信してサーバ処理を行い、終わったら戻るリンクをクリックするような動きをJavaScriptで実装しています。

 

 

ところが、この記述だと<a>タグのonclickは実行されるのですが、画面遷移は行われませんでした。

その辺りは以下の記事にも書かれていました。

LogicA jQueryでaタグのリンクをクリックさせる方法 − » jQueryでaタグのリンクをクリックさせる方法

 

今回は、上記の記事の解決方法とは別の方法を見つけたので紹介してみます。

 

不思議なことに、以下のようにするだけです。

<!--
$(function() { $('#submitBtn').click(function() { // なんらかのAjax処理 start
~~~ 省略 ~~~
// なんらかのAjax処理 end
    $('#back').trigger('click');
}); }); //-->
<input type="button" value="ボタン" id="submitBtn" /> <a href="/hoge/fuga"><span id="back">戻る</span></a>

<a>タグの内側の要素に対してtriggerを実行すると、その要素の親たちもクリック処理が順次行われていきます。

その過程で、何故か<a>タグのhrefによる画面遷移も行われました。

この方法の良いところはJavaScript側に修正を加える必要が無い点です。

 

 

なお、以下のような解決方法もあるようです。

jQueryでリンクをクリックさせたい時 - Qiita

<a href="/hoge/fuga" id="targetLink">It's a pit world</a>

<script>
$(function(){
  // 何らかの処理
  $('#targetLink')[0].click();  // ←コレがポイント
  // $('#targetLink').trigger('click');では動かない。

});
</script>

 

<a>タグの子要素をクリックさせる、という点で考え方は同じな感じでしょうか。

ちなみに、適当に書いたhref属性の中身が完全に一致していてちょっとびっくりしました。

三項演算子

ほとんど全てのプログラミング言語にはifとforが備わっています。

if文の場合、書き方に違いはあれど、以下のような形が基本です。

if (boolean) {
  // booleanがtrueの場合に実行される処理
} else {
// booleanがfalseの場合に実行される処理
}

判定結果によって処理を分岐させるために用います。

 

この条件分岐ですが、JavaJavaScriptC言語などでは以下のように書き換えることができます。

boolean ? trueの場合に実行される処理 : falseの場合に実行される処理;

簡単な条件分岐であれば1行で表現可能で、慣れてしまえば非常にシンプルです。

シンプルなんですが、「?」といい「:」といい記号であるため検索エンジンで調べることが難しく、知らないひとは意外と知らないようです。

 

このシンプルな条件分岐の記述は「三項演算子」または「条件演算子」などと呼ばれます。Wikipediaにも載っています。

条件演算子 - Wikipedia

名前だけでも覚えておくとあとで調べなおしやすいです。逆に、忘れるとなかなか調べられない難敵です。

Webサイトの表示速度を計測するブックマークレット

Webシステムのとある画面について表示速度が遅いという指摘を受けて速度改善を行ったりすることがあります。

「表示されるのが遅い」といっても原因はさまざまです。

 

リンクをクリックしてからサーバにリクエストが送信されるまでの時間。

サーバがリクエストを処理し、場合によってはDBに接続したりする時間。

クライアントにレスポンスを返却する時間とそのサイズ。

クライアント側でレスポンスを受け取ったあとhtmlを描画する時間。

htmlが描画されたあと、JavaScriptのonloadによって行われる処理時間。

 

クライアントやサーバ、ネットワークのスペックが低かったりすることもあります。

 

そんなときは、まずどこの部分に時間が掛かっているのかボトルネックを見つけることが重要です。

今回はその切り分けを助けてくれる素敵なブックマークレットを見つけたので紹介。

 

【これは便利】あなたのWebサイト表示のどこが遅いかを一発で調べるブックマークレット | 編集長ブログ―安田英久 | Web担当者Forum

javascript:(function(){%20var%20d=document;%20var%20s=d.createElement('scr'+'ipt');%20s.charset='UTF-8';%20s.language='javascr'+'ipt';%20s.type='text/javascr'+'ipt';%20s.src='//web-tan.forum.impressrd.jp/tools/pagespeedtiming/pagesppedtiming.js?t='+(new%20Date()).getTime();%20d.getElementsByTagName('head')[0].appendChild(s);%20})();

 

 上記のJavaScriptをブラウザのブックマークに登録しておき、計測対象のWebサイトで実行すると計測結果をわかりやすく解説してくれます。

ブラウザの開発者ツールでも解析は可能だと思いますが、とりあえずチェックしてみる、というお手軽さがなんともグッドです。

JavaScriptの無名関数で引数を渡す方法

jQueryなどのライブラリがある現在ではあまり使われなくなった(姿を変えた?)かもしれない無名関数。

そのjQueryがよくわからない衝突かなにかを起こしているのか、ノーマルなJavaScriptを書かなくてはいけない機会があったので復習。

 

参考:

無名関数をすぐに実行する(function(){})()の覚え書き [JavaScript] : ずっと工事中

JavaScript :: 無名関数に引数を渡す [Tipsというかメモ]

 

<a href="javascript:void(0);" onclick="javascript:(function(obj){alert(obj);})(this);">hoge</a>

後ろに付ける括弧に引数を渡せば、中のfunctionの引数に渡ってくるみたいです。

JavaScriptで乱数生成

JavaScriptで乱数を生成する場合、たいていはMath関数を使います。

具体的にはMath.random()という関数を使うことになります。

Math.random()

 

このままだと、0~1の間の少数がランダムで生成され、桁数も多くて扱いづらいです。

そこで、以下のように乱数の幅を固定します。

Math.floor(Math.random()*6)+1

Math.random()で生成された数値に6を掛けることで、通常生成される0~1の少数が0~5の幅に広がります。

あとは、Math.floor()で小数部分を切り捨てます。

具体的には以下のような感じ。

  • 0.1→0.6→0
  • 0.2→1.2→1
  • 0.3→1.8→1
  • 0.4→2.4→2
  • 0.5→3.0→3
  • 0.6→3.6→3
  • 0.7→4.2→4
  • 0.8→4.8→4
  • 0.9→5.4→5

サイコロなんかの場合は1~6の出目がありますので、Math.random()を6倍し、0~5になる揺れ幅に+1して1~6とします。

 

要するに、6分の1の乱数を生成したい場合は6倍、100分の1の乱数を生成したい場合は100倍にすれば良いわけです。

あとは、生成される乱数が0から始まることを考慮し、実際に使いたい値となるよう加減することになります。

 

たまに使うときに毎回調べてる気がするのでメモ。