javascriptで簡単に経過ミリ秒を取得する方法

javascript で日付をミリ秒に変換したい場合、

var date = new Date();
alert(date.getTime());
// 1235619446796

とするのが一般的だと思うのだけど、jquery を見ていたら、すっごいシンプルなやり方が書いてあった。

alert(+new Date());
// 1235619446796

日付インスタンスの頭に「+」を付けるだけ!日付オブジェクトは、四則演算するときに自動的にミリ秒変換して数値として計算するようだ。なるほど、うまいところを突いたなあ。さっすが jquery だ。

ちなみに「+」を取ると、単に Date#toString() の結果が出力されます。

alert(new Date());
// Thu Feb 26 12:38:04 UTC+0900 2009

でも、こうして書いてよくよく考えると、getTime() でも、そんなに面倒じゃない気がしてきた。すごく面倒くさがり屋さんにはオススメです!

javascriptでsubmitできない?

悔しいことにハマったので、メモ。

次のような感じで、javascriptでformをサブミットしようとしたら、エラーになってしまう。

<form name="addForm" action="/add" method="post">
<input type="button" name="submit" onclick="document.forms[0].submit()" value="送信" />
</form>

理由を聞いてみると、

document.forms[0].submit is not a function

関数じゃないって、そんなわけあるかい。javascriptの不審な動きに、仕方なくひとつひとつ探っていって、やっと分かりましたよ。formタグのなかに、「submit」という名前の要素を置くと、そっちを参照しちゃうみたい。ここでは、ボタンの名前に「submit」なんて付けているからダメだと。

言われてみれば、確かにそれはそれで正しい気がする。でも、まあ、もう少し優しい言葉を返してくれても良いんじゃないだろうか。同じ理由で、例えば、action や target という名前も、避けないといけないってことだよね。

回避策もありそうな気はするんだけどなあ。見つけたらエントリしまっす。

JavaScriptで外部CSSの値を取得する

JavaScriptで外部CSSで定義した値を参照する場合

var mystyle = element.style

ではなく

var mystyle;
if (document.defaultView && document.defaultView.getComputedStyle) {
    // firefox, opera
    mystyle = document.defaultView.getComputedStyle(element, '');
} else if (element.currentStyle) {
    // ie
    mystyle = element.currentStyle;
}

ってしないといけない。

恥ずかしながら今まで全然知らなかったけど、よく困らなかったなあ、自分。prototype.js には、Element.getStyle() というのがあるから、それを使えば良いのだけど、やっぱり基本原理みたいなものを押さえていないと気持ち悪いので。

詳細はこちらが、スゴイ詳しいです。amachang 氏、さすがの内容。

getComputedStyle について調べてたら深みにハマったのでメモ - IT戦記

removeChildではまる

NodeListのノードをremoveChildで順番に消していこうとしたら、半分くらい残る。なぜ。

var tbody = document.getElementsById("hoge");
var nodelist = tbody.getElementsByTagName("tr");

var len = nodelist.length; for (var i = 0; i < len; i++) { tbody.removeChild(nodelist[i]); }

上手く説明できないけど、nodelistの数値インデックスの関係がおかしくなっている。getElementsByTagNameが返すNodeListは参照で、ノードを削除していくごとに、動的にNodeListの長さも変わっていくのかな。だから、削除していくと、「そんな数字インデックスに該当するノードは無いよー」ってなってるっぽい。

ということで、ノードの削除は、常にNodeListの先頭のものを対象に実行するとキレイに行く。

while (nodelist.length > 0) {
    tbody.removeChild(nodelist[0]);
}

仕組みが分かれば、そりゃそうだって話なんだよね。リスト操作の基本か。こういうこと考えると、Iteratorがあると便利なのかもしれない。

続きを読む "removeChildではまる"

SSL対応Google Analytics

httpsな環境でGoogle Analytics用コードを埋め込んでいると、IEでアクセスしたときに次のようなアラートウィンドウが開く。

ie_alert.gif

「このページにはセキュリティで保護されている項目と保護されていない項目が含まれています。」と、ちょっと親切なふりをしているが、これってユーザーに何かメリットがあるんだろうか。どちらかと言えば、煩わしくて邪魔だと思うんだけど…。

気になったので調べたら、回避策があった!

Google AnalyticsをHTTPS(SSL)なページで使う

× http://www.google-analytics.com/urchin.js
○ https://ssl.google-analytics.com/urchin.js

SSL対応のUrchinサーバーがちゃんと用意されているとは、さすが。

DOCTYPEでjavascriptの挙動が変わるなんて

実験的に書いていたスクロールいじり系のスクリプトが、アプリケーションに組み込んだ途端に動かなくなった。scrollTopの値が常に0になる。むむぅ。

ハマりそうになって調べたら、どうもDOCTYPEによって、scrollTopの参照の仕方を変えないといけないとのこと。DOCTYPEの変更でjavascriptの挙動まで変わるとは思わなかった。理屈を言われれば道理が通るけど、しかしこれは反応できないッス…。

DOCTYPEを指定しない場合は、

document.body.scrollTop

DOCTYPEを指定する場合は、

document.documentElement.scrollTop

これで値を取得しないと、正しく参照できないと。他にもこの手のプロパティは同じような動作するんだろうなあ。覚えておかないと、ハマりそう。

参考:ブラウザのスクロール量を取得するには?

delete 演算子の意味

javascript の delete 演算子の使い方を勘違いしていたっぽい。

てっきり不使用オブジェクトを削除することで、メモリを開放できるもんだとばかり思っていた。ところが、実際には undefined で上書きするだけで、メモリはまったく開放されない。結局、javascript におけるメモリ管理は、各クライアントの GC にまかせるしか無いのか。うーん。

Ajax の興隆以来、よく javascript コードを見るようになった。そこで気付くのが、多くの人が富豪的アプローチをしていること。onmouseover イベントを document に対して attachEvent しちゃうのかー、贅沢すぎー、みたいな。

今やクライアント側の性能が十分だから、あんまり気にしなくても良いのかもしれないけど、javascript で out of memory 的なことって起こるんだろうか。どこまで耐えれるのか、落ち着いたら実験してみたいなあ。

location.hashの書き換えでリロードが発生

Yahoo!Maps のように、FlashとJavascriptを連携させて、URLのhashを書き換えていこうと思ったら、ずっこけた。悪名高きOperaで location.hash を書き換えると、勝手に画面がリロードされてしまう。なぜ。

いろいろ追っていった結果、現在のhash値と代入する値が同一の場合、リロードになるっぽい。どんな仕様ですか。しょうがないので、if文で分岐するがよろし。

function setHash(_value) {
    if(location.hash != "#" + _value) {
        location.hash = _value;
    }
}

「これはバグだ!」と思ったら、なんか Safari でも同じような動きになる。スタンダードって何だろうとか考えさせる、罪なブラウザたち。やめて欲しい。

続きを読む "location.hashの書き換えでリロードが発生"

HTMLからFlashへ変数が渡せない?

HTMLからFlashに変数を渡すには、2通りの方法がある。ひとつはFlashVarsを使用する方法、もうひとつはSWFファイルURL指定時に、クエリーとして変数を付加する方法。

// 後者抜粋
<param name="movie" value="deftrash.swf?hoge=foo" />
<embed src="deftrash.swf?hoge=foo" ... />

前者は FlashPlayer6 以上で、後者はもっと前の世代でもOK。そんなわけで、後者の方法を使用している人も多いはず。ところが、ここで落とし穴。変数の文字列に「#」が含まれていると、Operaでは、「#」以降の文字列を渡すことができない!(FlashVarsの方法では大丈夫っぽい)

どうやらURLエンコーディングしてあげる必要があるみたい。

// JavaScript で対応する場合
<script type="text/javascript">
document.write("<param name=\"movie\" value=\"deftrash.swf?hoge=\" + escape("#foo") + "\" />");
document.write("<embed src=\"deftrash.swf?hoge=" + escape("#foo") + "\" ... />");
</script>

location.hashをFlash側に渡そうとして、コレにすごいハマった。Operaとかスゴイ嫌いだよ。ううう。

正規表現マッチの真偽値の取り方

これまで、javascript で正規表現のマッチング結果を得るときは、バカのひとつ覚えで String.match を使っていた。

var str = "12345";
var reg = new RegExp(/123/);
if(str.match(reg)) {
    // マッチしたときの処理
}

でも、match関数の戻り値は「最初にマッチした部分の文字列(マッチしなかった場合は null)」 で、純粋にマッチしたかどうかを知りたい場合では、わずかにリッチすぎる。そのような場合は、RegExp.test (戻り値はtrue / false) を使うのが良い。

var str = "12345";
var reg = new RegExp(/123/);
if(reg.test(str)){
    // マッチしたときの処理
}

続きを読む "正規表現マッチの真偽値の取り方"

document.onload なんてありません

ちょっと切ない JavaScript の話。

onload で複数の処理を行うために、Observer パターンを使おうと思ったわけです。ファサードになるファンクションを設けるのも良いけど、融通が利きにくいし。

というわけで、document にリスナーオブジェクトを登録&実行したんだけど、これがピクリとも動かない。原因は、document.onload が存在しないこと。何故。じゃあ、body タグに書く onload は何に対応するんだ。色々イジった結果、自作の処理とバインドできる onload は、window オブジェクトのそれだけの模様。

document.writeln(document.onload); // 結果は undefined
document.writeln(window.onload); //結果は null (バインド可能)

ちなみに、一番上のスコープで this と書くと、window を指すみたい。ということで、

this.addEventListner("doSomething", lintener1);
this.addEventListner("doSomething", lintener2);
this.onload = this.dispatchEvent(
                  {type:"doSomething", target:this}
              );

こんな形になりました。厄介だ。

Webアプリのテストには Selenium

webアプリケーションテストツール seleniumがヤバすぎる

JavaScriptベースのWebアプリケーション用テストツールらしい。各種ブラウザ経由で、サクサクっとテストできそうな雰囲気。JUnitも良いけど、あれは仕様変更に弱いっていうか、仕様変更が相次ぐと置き去りにされる傾向にあるからな…って、それはそれでマズイ話だけど。

Ajaxもびっくらこいたけど、このseleniumもスゴそう。一部ではJavaScriptにダメ言語のレッテルを貼り付けているけど、使い方次第なんだろうね。selenium、どっかで使ってみよう。

オブジェクト初期化子

JavaScriptのEventまわりについて調べていたら、見たことない記法が出てきた。なんか変数の後ろにコロン付けて、それに続けてfunctionとかあるんだわ。型みたいなの。検索してみると、オブジェクト初期化子というものらしい。

var hoge = {
    doMoge : function(_argument) {
        alert(_argument);
    }
}
hoge.doMoge();

オブジェクト初期化子を使うと、Objectのインスタンス生成時に、そのプロパティの初期化ができる模様。上の例は、プロパティを関数で初期化してみたところ。

単純化すると、こういう話。

// 次の2行は同じ意味
var hoge = new Object();
var moge = {};

もちろん new してから代入しても同じだけど、明示的に初期化できるから、こっちの方がコードの可読性は良い。単純化の例だと逆効果になりそうだけど、ちゃんと使えば素敵かもしれない。まあ、最近クラス化が基本になってるから、使い場所ないんじゃないかって、専らの噂だけどね。

[参考] Under Translation of ECMA-262 3rd Edition オブジェクト初期化子

続きを読む "オブジェクト初期化子"