JavaScript の食えない事情

JavaScript は Netscape社 が Navigator で最初に実装し、 Microsoft社が JScript という名称で Internet Explorer に実装しています。

Microsoft社は JavaScript の仕様を標準化団体 ECMA による ECMA262 に準拠する言語として位置付け、 Internet Explorer の機能を扱える各種機能( 主に ActiveX 及び VBScript ) 追加を行なっています。

JavaScript は ホームページにダイナミックな動きを演出する上で、 簡単に実現できる手段を提供しているわけですが、 2つのブラウザの品質の面で混乱を引き起こしていて、 JavaScript を使う上で安易に全ての機能を使えない事情があるのが現実です。

結論を言えば、現状では JavaScript をサポートしていないブラウザが存在することも含めて、 完全に不特定多数から参照されるドキュメントに JavaScript は向いていないと思います。 不特定多数から参照されるドキュメントには JavaScript がサポートされていなくても 特に問題にならない箇所で使用し、使う機能も JavaScript1.0 の仕様に限定した方が無難でしょう。

JavaScript が最もその機能を発揮できるのは、使用するブラウザの種類やバージョンに ある程度の制限ができるイントラネットなのかもしれません。


目 次

IE のバージョンのウソ
IE は JavaScript のバージョンに関してウソをつく
NN のバージョンのウソ
NN3 はバージョンチェックせずに SRC ファイルを読み込む
バージョン指定の意味
SCRIPTタグでバージョン指定すると何が変わる?
コンパイラ その1
IE3 は大文字小文字を区別しない
コンパイラ その2
IE3 はメソッドとプロパティを区別しない
コンパイラ その3
NN4 は SCRIPTタグの type 属性を見ていたのね〜
メソッドの実装判定
メソッドの実装判定を if文 で安易に行うとエラーになるものが...
名称付きウィンドウと target 指定
IE のウィンドウ管理ってヘン
セキュリティパッチの悲劇
IE4 にセキュリティパッチをあてると opener がアクセスできなくなる!?
ウィンドウのリサイズ
NN でリサイズ操作をすると事態が複雑に...
href と onClick
アンカータグ( A タグ )の href と onClick では何が違う?
setTimeout の返り値
setTimeout の帰り値はバージョンによって型が異なる
history管理
FRAME で history を変更すると NN は混乱する
コードの扱い
NN では JavaScript で生成した document が再評価されることがある
疑惑の document.write メソッド
NN では 生成した document の管理がおかしい?
疑惑の document.write メソッド ふたたび
NN では <link rel="stylesheet"...> を document.write すると...
Date の値
あれ?いつからそ〜なの?
Date の値 その2
あれ?いつからそ〜なの? ... その2(笑)
lastModified の値
「戻る」操作で lastModified の値がなくなることがある
lastModified の値 その2
IE は lastModified の値が 9時間ずれる
lastModified の値 その3
IE4 は lastModified の値が 西暦下2桁で返ってくる
lastModified の値 その4
IE は lastModified のデータがない場合調整した値を返す、みたい...
referrer の値
IE3 は referrer の値がウソ
referrer の値 その2
別にウソをついていなくても、結構ウザッたい
hash の値
IE3 では hash の値は使えない
arguments の値
IE, NN3 の arguments は Array じゃないの?
Form で送信するデータ
IE ってなんでワザワザ UNICODE にしたんだろう?
Form の target指定の不思議
なんで NN4 で文字化けが発生するんだろう...
イベントの発生順
ブラウザにより FORM のイベントは発生順が異なる
イベントの発生順 その2
NN3 と NN4 では BODY属性のイベントハンドリングが変わった?
イベントの発生順 その3
onUnload イベント発生時には既に unload 状態になっていることがある
他のウィンドウへのアクセス
あちら立てれば、こちら立たずの典型〜
ページの印刷
フレーム構成のページを印刷する場合の苦労
Java との連携
LiveConnect はブラウザ・バージョンで動作が異なる
パフォーマンス
色々なケースで重い処理が走る
パフォーマンス その2
IE4 は実は NC4 よりすごく遅い
パフォーマンス その3
IE4 は アニメーション GIF が嫌い?
パフォーマンス その4
IE4 は レイアが苦手?
セキュリティ
IE3 の知られざる(?)セキュリティホール
二つの顔を持つJavaScript
ECMA-262 って一体ナニ?
その他のコマゴマとしたバグ
バグが多いのも困るけど、回避できないのは更に困る
2つのブラウザに対するJavaScriptの評価
JavaScript に関する独断の評価です f(^^;

IE のバージョンのウソ

IE の JScript は、もともと NN に実装された JavaScript の互換言語として開発されました。

そのためか userAgent も「Mozilla/4.0 (compatible;...)」と言った表記になっています。
この意味で IE は JavaScript のバージョンに関してほとんど常にウソをつきます。

このために、「language="JavaScript1.1"」といった記述では不十分で、 ブラウザの種類とバージョンを検査して JavaScript1.1 又は 1.2,1.3 のロジックの中に IE用 の回避ロジックを設けなくてはなりません。

#> try...catch 構文に至っては IE5.0 でサポートするんだから DOM Level1 に合わせて欲しかった... (-_-;


NN のバージョンのウソ

NN3.x は SCRIPT タグに SRC の指定がある場合、 LANGUAGEが JavaScript1.2 と指定されていても読込むバグがあります。 因みに、バージョンは何であっても SRC が読込まれます。 詳細については DevEdge Online の 「Introduction to Cross-Browser, Cross-Platform, Backwardly Compatible JavaScript and Dynamic HTML」 を参照して下さい。

#> し、知らなかった。 m(..)m


バージョン指定の意味

SCRIPT タグで JavaScript のバージョンを指定すると バージョン毎の切り分けができます。 これは、何も追加された構文だけではなく、変更された関数などにも当てはまるようです。

例えば、 Array メソッドは JavaScript1.3( NN です ) では 引数が数字1コの場合、配列数を意味するようになりましたが、 JavaScript1.2 と宣言すると JavaScript1.2 の I/F の動作になります。

これは便利かもしれません。 が、上の例だと同じ JavaScript1.2 でも IE4.0 では ECMA-262 の I/F ですから NN版とは動作が異なります。

また、IE でも同じような動作になるかどうかは未調査です。

#> まあ、互換性にまで手の回らない MS のことですから... f(^^;


コンパイラ その1

IE(少なくとも3.02迄)はコードの大文字・小文字を同一視します。 このため、IE で動作したとしても NN で動作しない場合があります。


コンパイラ その2

IE(少なくとも3.02迄)はメソッドとプロパティを区別しません。 このため同じ名称で変数と関数を定義しても、同じ名称のものはオーバライドされるため、 NN で動作したとしても IE で動作しない場合があります。 また、この場合にはエラーの発生した行番号が出ないケースもあり、 エラー箇所の発見にはかなり時間がかかることもあります。


コンパイラ その3

HTML4.0 では SCRIPTタグの言語は language 属性を廃止し、 type 属性で指定することになっています。

そこで、この仕様に準拠して

<script language="JavaScript1.2" type="text/javascript">

などと、指定すると困ったことになります。

具体的に言うと、比較的最近のブラウザ( NN4, IE4 )は SCRIPTタグの type属性 を解釈するのですが、 困ったことに language 属性のバージョン指定を無視して、従来記法の

<script language="JavaScript">

と指定したのと同じになってしまいます。

元々 NN3 では( IE3 はインストール環境がないので確認できない ^^;) type属性は無視しますから language属性の指定が有効になりますので、 今のところクロスブラウザなスクリプトであれば実害はなさそうなのです。

が、NN専用のスクリプトで Array コンストラクタの変更仕様にかかわるコードや IE専用のスクリプトで try...catch 構文などを使用したコードは問題が出ると思われます。

最も単純な回避策は、従来通り

<script language="JavaScript1.2">

と言う具合に、type属性を記述しないことですが、 将来 language属性が本当に廃棄され、type属性に version パラメータが採用された時に 現在のブラウザが生き残っていると、さんざんな目に遭うかもしれません。 f(^^;

注 version パラメータは W3C HTML4.01 の仕様には定義されていませんが、 現在 Mozilla( NN6 )で採用されています。

language属性 が廃棄された場合にバージョン指定ができないと ECMA Script の仕様変更が問題になりますので、 何らかのバージョン指定が出てくると思われます。

因みに Mozilla( NN6 )での type属性でのバージョン指定は以下の形式ですが、 反対にこの指定をすると現在のブラウザ( NN4, IE4/5 )は別の言語と判断するのか、 一切実行しません。

type="text/javascript;version=1.5"


メソッドの実装判定

ブラウザの種類を判定するために、しばしばオブジェクトやプロパティで判定する場合があります。

よく使用される判定には document.all や document.layers などがあり、 navigator.userAgent などで行うより簡単に判定できる点で優れています。

これは、対象とするオブジェクトやプロパティが実装されていないければ undefined に なることを利用し、該当のものが undefined であれば、それがサポートされる以前の ブラウザであると判断することができます。

しかし、メソッドに対して安易に行うと、実装が中途半端なのか "not a function" というようなエラーになるメソッドがあります。

一例としは getFullYear メソッドで、 このメソッドはブラウザや JavaScript のバージョンには対応していない (*1) のでそれが実装されているかどうかを厳密に、しかも簡単に行うには Date オブジェクトに getFullYear メソッドが実装されているかどうかを直接調べることになります。

*1 getFullYear メソッドは Win版 NN では NN4 の途中( JavaScript1.2 の途中 )から 実装されています。

そこで、getFullYear メソッドの実装判定に

var date = new Date();
if(date.getFullYear)
    :

とすると、エラーになるブラウザがあります。

この場合はしょーがないので、 以下のようにすると安全に判断できるようです(*2)。

var date = new Date();
if(date.getFullYear?true:false)
    :

*2 「ようです」というのは全てのプラットフォーム・ブラウザで動作確認したわけではなく Win版 IE4/5, NN4, Linux版 NN4 のみだからです。
確か、IE にも似たようなメソッドがあったのですが... 忘れた f(笑;


名称付きウィンドウと target 指定

表示しているページから別ウィンドウにリンクなどを表示するとき target 指定を使用します。

単に target 指定だけだと、 表示中のウィンドウと同じ装飾、同じサイズのウィンドウが開かれます。 そこで、ウィンドウの装飾を変えたい、開かれるウィンドウサイズを変えたい、 等の事情がある場合は JavaScript を使用することになります。

例えば、こんな感じです。

win = null;
features = 'width=200,height=100,resizable';
function createWindow(){
  if(win==null || win.closed)
    win=window.open('','winA',features);
}
    :
<a href="A.htm"
   onClick="createWindow();" target="winA">Link</a>

このスクリプトは NN ではうまく動作しますが、 IE4 では window.open したウィンドウとは別に新規ウィンドウが開かれます。

どうやら、IE4 は target 指定で開いたウィンドウと JavaScript で開いたウィンドウは 同一名称でも別管理をしているようです。 (-_-;

しょうがないので、この場合は次のようにします。

win = null;
features = 'width=200,height=100,resizable';
function createWindow(url){
  if(win==null || win.closed)
    win=window.open(url,'winA',features);
  else
    win.location = url;
}
    :
<a href="A.htm"
   onClick="createWindow('A.htm');return false;"
   target="winA">Link</a>

単に、リンクの場合はこれでも良いのですが、 FORM のターゲットで method が POST の場合なんかは、 このスクリプトは通用しません。 (x_x;

しょーがないので、別ウィンドウに表示して、ロード完了でリサイズしますか(笑)。

注 この問題は IE5 でも発生する場合があるようです。

IE4 とは異なり、常に発生するわけではなくネットワーク環境かバージョンに依存するようです。

因みに、確認用サンプルを作成しましたので、興味のある方はこちらにどうぞ。


セキュリティパッチの悲劇

IE には数々のセキュリティに関するバグがあり、頻繁にパッチが出ています。

まあ、様々なウィルスやワームが闊歩する現在ではパッチしない訳にはいきません。

しかし、中にはやりすぎ(笑)のパッチがあるようで、 IE4 で window.open() で開いた子ウィンドウから、 親ウィンドウの資源がアクセスできなくなる場合があるようです。

それはこんなスクリプトで検証することができます。

window.open('hogehoge.htm','foo').focus();

つまり、window.open() で開いたウィンドウを最前面に出そうと window.focus() する場合です。

この現象は IE4 でのみ発生し、他の IE5, IE6 では発生しないようです。

対処方法は、単に focus() しなけりゃいいんですけどね。 f(^^;

#> 必要なら子ウィンドウ側で onLoad時に focus() すれば良いのです

注 この問題の発生する IE4 のバージョンは、 少なくとも IE4 SP2 に数々のパッチを充てたもの( 2001年 9月23日時点で最新の状態 )なんですが、 「バージョン情報」を見ると「Update versions」欄がウィンドウからはみ出して正確にはわかりません(爆)。

そろそろ IE4 を諦めてバージョンアップするかなぁ...

因みに、確認用サンプルはこちら

注 IE4 は元もとウィンドウ管理に問題がありますが、 通常では window.focus() がセキュリティに関連するとは思えません。

これは、ひょっとすると正しくない場所を修正している結果かもしれません、 つまり、パッチはこれからも出続けるかも
あっ、IE6 が出たからサポート対象外か... f(^^;


ウィンドウのリサイズ

NN ではウィンドウをリサイズすると JavaScript で生成したドキュメントやオブジェクトが無効になり、 表示が崩れたりエラーになったりします。

これは、NN の仕様というより単にバグというやつでしょう。 f(^^;
JavaScript の内部で変数やオブジェクトが無効になっているかどうかを判断する基準がないので、 苦肉の策として、ウィンドウをリサイズした場合に reload する手法を採るのが一般的のようです。

しかし、この判断自体色々と難しい問題があります。

安易に考えると

<body ... onResize="location.reload();">

で良いように思いがちですが、NN の resize イベントにはクセがあるようです。

つまり、対象としているドキュメントを表示しているウィンドウにスクロールバーが 表示されているかどうかで resize イベントの発生の仕方が異なります。

スクロールバーがない場合
リサイズした場合に resize イベントが発生する

スクロールバーがある場合
初期表示時に resize イベントが発生する
( もちろんリサイズした場合にも resize イベントが発生する )

そこで、スクロールバーが表示される場合には、一般的に

resize_count=0;
function resize(){
  if(++resize_count>1) location.reload();
}
<body ... onResize="resize();">

とするようです。

因みに、この JavaScript Tips集では上記方法は採っていません。
これは、スクロールバーが表示されるかどうかが分からないためで、 その上アタシが不精者なもんで... f(^^;

代わりに

<meta http-equiv="Expires" content="0">

を追加しています。

注 上の Expires の指定はネットワーク越しの場合( http:// )に有効で、 ローカルファイル( file:// )の場合は機能しませんので注意して下さい。

また、確認時はキャッシュをクリアしてから行わないと、 NN のキャッシュ制御のバグのためにウィンドウリサイズ時に、 古いデータがロードされてしまいますのでお忘れなく。 f(^^;

注 IE の場合でもウィンドウリサイズしても表示はされるが再配置されない、 と、ある方からの指摘されましたので、蛇足^H^H補足しておきます。

IE では配置した時に位置やサイズをウィンドウ等に対するパーセンテージで指定されていれば、 ウィンドウリサイズ時に再配置されますが、ピクセル値などの絶対値で指定した場合でも 再配置される訳ではありません( 再計算するためのスクリプトが動作する訳でもない )。

従って、このような場合( クロスブラウザでは殆どこのケースか? f(^^; )には やはり、onResize を指定して location.reload する必要があります。

また、IEでの Expires の指定は、リサイズ操作には全く効果がないので、 IE では reload でなければなりません。
但し、 NN のようにスクロールバーに絡む問題がある訳でもないので、多少楽かも。 ( クロスブラウザなら更に複雑さが増す... (T_T) )


href と onClick

Aタグ で選択時に JavaScript を実行する方法には、 一般的に href で JavaScript を記述する方法と onClick で記述する方法の2種類があります。

両者には違いがあるのでしょうか?

すぐに気がつく違いは JavaScript を無効にした場合でしょう。 href で記述した場合は単にクリック動作が無視されますが、 onClick で記述した場合は href の値が有効になります。

それ以外に注意しなければならない挙動は href に JavaScript を記述した場合は、 アニメーション GIF などの動作が停止することでしょう。

アンカータグを他のページへの移動以外の目的( 例えばイメージを変更するなど ) で使用する場合に、前述の JavaScript の有効性の挙動を利用して href に記述すると、 JavaScript が無効の場合には記述が単に無視されるので良いと思いがちですが 同じページにアニメーション GIF などを使用している場合には停止してしまいます。

これは少しヘンですが、バグと言うよりも仕様だと思われます ( IE4.01, NN3.0, NN4.0 で確認)。


setTimeout の返り値

setTimeout の返り値は同じブラウザでもバージョンにより、 オブジェクトであったり数値であったりします。

これは、たぶんセキュリティ絡みの仕様変更( NN3〜NN4, IE3〜IE4 )だと思われますが、 このために setTimeout の返り値を格納した値が有効かどうかの判断に使えません。 これは、コンパイラの問題とも関連してくるのですが、 返り値がオブジェクトの場合の未定義値は「null」で数値は「0」に設定/判定しないと コードのコンパイル時にエラーになる可能性があるためです。


history管理

このTips集にも多用しているのですが、 「戻る」のリンクに直接 URL を記述せず JavaScript でブラウザの履歴を戻る (history.back() や history.go(-1) など)を使用すると NN ではかなりの確率で履歴が乱れ、 ブラウザが異常終了する原因になります。

また、NN ではフレームを構成しているページ内での動作は一見正しく動いているように見えても、 管理上変更されていない場合があります。 ページの表示と内部管理が食い違えば、異常終了も当然ですけどね。 f(^o^;

そんなわけで NN でこのページを見ている方は絶対に「戻る」リンクをクリックしないで下さい。


コードの扱い

JavaScript を実行し、その中で HTML 文書を生成するようなコードの場合、 NN では実行後の再描画で再評価され、エラーが発生する場合があります。

エラーが発生する確率を減らすには、タグを必ず対にして生成した方が良いようです (すみません。経験的な判断です)。


疑惑の document.write メソッド

上の「コードの扱い」とも関連するのですが、NN4 では文法上合っているにもかかわらず、 ローディング中に文法エラーが出る場合があります。

この場合、リロードを実行すれば正常になるのですが、原因が定かではありません。

「左の"献立表"でエラーが出る」とある人からのメールで言われ、 色々と考えてみると、以下の疑惑が浮かび上がります。

つまり、 document.write メソッドは出力する文書を複数に分割して

document.write(s1,s2,s3);

というように指定できるのですが、 問題がでるケースはこれらの一部が出力される前に評価された結果のように思えるのです。

そこで、上記のような出力の指定はやめ、

document.write(s1+s2+s3);

としてみることにしました。

#> タイミングの問題なもんで、 修正しても直ったかどうかがよく分からない... f(^^;;;

注 やはり、これでも充分ではありませんでした (-_-;
発生するケースの特徴もよくわかりませんが、ひょっとすると

・外部JSファイルを document.write している

くらいでしょうか

コレっと言った回避策はありませんので試行錯誤のみですが、

・document.write の位置を HTML の最後の方にしてみる
・スクリプトをあまり密に記述せず適当にスペースをいれる
・document.write の数を少なくしたり多くしたりしてみる

なんてのが良いかも... f(^^;


疑惑の document.write メソッド ふたたび

またもやメールで教えていただいたのですが、 次のコードを使うと HTML ソースの一部が壊れると言うものです。

document.write('<style rel="stylesheet" ...>\n');
または
document.writeln('<style rel="stylesheet" ...>');

この現象は比較的はっきりしていて、 link タグによる外部スタイルシートの指定を document.write する際 タグ以外のコードをタグの後ろにつけて一緒に出力すると document.write している scriptタグの後ろで、HTMLソース上の 4KB 境界( 4096bytes の整数倍 )の位置に linkタグの後ろの文字列が挿入されるものです。

#> ちょっと条件が複雑だけどわかる? f(^^;

つまり、挿入された文字が改行コードの場合クラスなどの名称やファイル名など 改行コードを含んではいけない場所や preタグなどに挿入された場合、 指定したスタイルが利かなかったり、変な位置に改行される、表示されないなどの 現象になるでしょうし、JavaScript のコード内であれば意味不明のエラーが 発生することになります。

回避策は単に document.write で link タグのみ出力し、 その後にも出力が必要であれば別途 document.write すれば良いと思われます。

#> この現象も、一説には挿入位置が変わったり挿入されない場合があるなど いろいろな現象になるというものもあるようですが、 自分で確認したところでは安定して(笑)間違った位置に挿入するようです。

また、このような現象が発生するタグが他にもあると聞いていますが、 現在のところ発見していません。

もし、この現象の詳細と確認がしたければ こちらでできます。

#> でも、これで document.write の疑惑のすべてが解明されたわけではないと思うゾ f(^^;


Date の値

日付は Date コンストラクタで生成しますが、 生成したオブジェクトの文字列表現( toString )はブラウザ・バージョン依存のようです。

各ブラウザで new Date() したオブジェクトを document.write すると以下のようになりました。

NN3.01 Gold [Ja] (Win98)
Sun Oct 17 19:34:01 PST 1999

NN4.7 [Ja] (Win98)
Sun Oct 17 19:34:01 GMT+0900 (???? (?W????)) 1999

IE4.01SP2 (Win98)
Sun Oct 17 19:34:01 UTC+0900 1999

いやあ、見事に違いますね〜。

よく見ると、NN4.7 の文字列には変な文字列が含まれます。 類推ですが、これは Timezone のようです。

本来、アメリカなどの夏冬時間がある場合には「Pacific Daylight Time」などの文字列が 表示されるようですが、日本にはないので不定の文字列が出ているのかもしれません。

また、こんな文字列が Date.parse できるのかと思って parse してみると チャンと parse できました。 f(^^;;

Date オブジェクトとそのメソッドは ECMA-262 で規定されているのですが、 例によって、 toString のフォーマットまでは定義されていませんでした。

#> こんなんで、使い物になるんだろ〜か

因みに、toString() にはこのような文字列が含まれますが、 toLocaleString(), ToGMT/UTCString() には含まれません。 やはりバグでしょう。 f(^^;


Date の値 その2

Date オブジェクトを生成する場合、通常は現在時刻を取り出すと思いますが、 日付指定をする場合には注意が必要です。

つまり、new Date(yy,mm,dd,hh,nn,ss) とした場合の yy,mm,dd,hh,nn,ss は 一体いつの時刻かが問題になる場合があります。

試しに alert(new Date(2000,0,1,0,0,0)); を実行してみてください。

NN4 では多分 "Sat Jan 01 00:00:00 GMT+0900" になると思いますが、 NN3 では "Sat Jan 01 00:00:00" になります。

つまり、パラメータとして指定する日付が地域時刻か標準時刻かの違いがあるわけです。

更に、 new Date(70,0,1) を実行すると NN3 では異常終了します。

これは、多分指定した時刻を地域時刻としてとらえ標準時刻に変換する過程で演算結果が 負の値になるためと思われます。

注 new Date(70,0,1,8,0,0) は異常終了しますが、 new Date(70,0,1,9,0,0) は正常(?)に動作します。

#> 然し、ヘンですね〜。昔は同じNN3 でこのように異常終了することはなかったのですが...

当時との差と言えば、当時が Windows95 + NN3 で 現在が Windows98 + NN3 くらいです。 ひょっとすると、異常終了する直接の原因は OS の差かもしれません(笑)。


lastModified の値

NN/IE 共にページを表示した後で、他のページに移り、その後戻ると、 時々 lastModified の値が「0」になる(基準日の日付になる)ことがあります。

また、IE3.02 では、この値はローカライズされた値(つまり、日本なら日本語表記) の不完全な値が戻りますが、この値を date オブジェクトとして parse することができません (つまり、parse 関数はローカライズされていない f(^^;)。


lastModified の値 その2

IE のあるバージョン(3.02 の一部と IE4 全て)と Mac版 NN4 では lastModified の値は正確ではありません。

この現象は以前から知ってはいたのですが、 現在もこの問題が残っているとは思っていなかったので挙げていませんでしたが、 ある方からメールで相談を受けたこともあり一応載せることにしました。

これは lastModified の値が標準時刻で通知される現象で、理由としては2つ考えられます。

1. サーバが送出する Last-Modified ヘッダの問題
Web サーバの中には参照されたドキュメントの最終更新日として送出する Last-Modified ヘッダが正しくない場合があるようです。

この場合は IE のみならず NN でも間違った時刻として通知されます。

2. Last-Modified ヘッダの解釈と表現の問題
Web サーバが正しい Last-Modified ヘッダを送出したとしても、 ブラウザが解釈し、文字列として変換する際のフォーマットが正しくない場合があるようです。

つまり、ブラウザが更新日を文字列として表記する際、標準時刻として表現する場合と 地域時刻として表現する場合( ブラウザ依存みたいです )があり、 更に、標準時刻の場合に "GMT" や "UTC" など表記がないために地域時刻表現と差がなくなり、 document.write などでそのまま出力してもどちらか判定できない ( 当然、 Date.parse メソッドを使用しても間違った時刻になります )ことに依るようです。

1. の原因に起因する場合は Web サーバの設定(?)を正しくしてもらうこと 以外にありませんが、2. の原因については JavaScript でも複雑になることを厭わなければ 対応することができます。

対応方法のサンプルについては「最終更新日」を参照してください。

#> SSI や CGI が設置可能なサーバであれば、 JavaScript で対応するより SSI や CGI で対応する方が遙かに楽です。

もし、SSI や CGI が設置できない場合は、厳密さにこだわらず、 そのまま表示しちゃうのが良いと思います。

どうしても厳密にしなけりゃならない、可哀想な方だけが JavaScript による解決をするくらいでしょうか(笑)。


lastModified の値 その3

いやぁ、驚きました。 f(^^;

MSIE4.0+SP2( 4.72.3612.1713:Win95/98版 ) でもやはり、Y2K問題はありましたね〜。

今まで気がつかなかったけど、 document.lastModified の年の値は西暦下2桁なんですね〜。

#> 年号を西暦下2桁ってのは反則じゃないの?

そこで、更新時刻が 2000年を過ぎたファイルの lastModified の値を parse すると見事に 1900年になります。

#> これだと、さすがに getFullYear メソッドでも補正できない...

実はこのサイトの最終更新日は JavaScript で lastModified を parse して 作成しているので、いきなり「最終更新時刻:1900年 1月 4日」なんて言われちゃって... f(^^;
因みに、確認できるブラウザで調べてみるとこんな風になりました。

BrowserlastModified の結果
IE401/04/00 18:57:24
IE501/04/2000 18:57:24
NN301/04/00 18:57:24
NN4Wednesday, January 04, 2000 18:57:24

ってことで、NN3 も同じでした( これは当たり前か... )。


lastModified の値 その4

「その2」でも紹介しているように lastModified の値はサーバから送出される Last-Modified ヘッダ(HTTP プロトコル)の値を JavaScript から参照できるようにしたものです。

ではこの HTTPヘッダ情報が送出されない場合はどのようになるでしょうか?

一般的には時刻データが "0" を示すため Date オブジェクトの基準日( 1970年 1月 1日 ) になると思われています。

#> と、言うより私がそう思っていました f^^;

しかし、IE では違っていたようです。
つまり、IE4 以降( IE3は不明 )では lastModified の値は現在時刻を示します。

もし、これらの動作を確認したいなら こちらで確認できます。

そこで、いろいろなブラウザについて Last-Modified ヘッダが送出されない場合の lastModified の値を調べてみました。

BrowserOSlastModified の結果
IE4Win02/16/2002 03:34:56
IE5.xWin02/16/2002 12:34:56
IE6Win02/16/2002 12:34:56
IE5.xMac OS 9/XSat Feb 16 12:34:56 2002
NN3.01Win01/01/70 09:00:00
NN4.78WinThursday, January 01, 1970 09:00:00
NN4.77LinuxThu 01 Jan 1970 09:00:00 AM JST
NN4.7Mac OS 9Jan 1 00:00:00 1970
Mozilla 0.9.8AllJanuary 1, 1970 GMT

プログラム開発上で自然なのは基準日が表示される方だと思いますが、 Last-Modified が送出されないケースを CGI 出力データであると考えれば 現在時刻を表示する方も納得ができます。

これらの違いはバグというより考え方の違いのようです。

#> ホントはどれを正解と言うべきか、W3C DOM2 にお伺いをたてたところ、 document.lastModified なんて定義されていなかった(笑)。
そー言えば Date.toString のフォーマットも ECMA で定義いていなかったっけ。

#> まあ、Last-Modified が送出されないページ上で lastModified を使用するケースは 検索エンジンのキャッシュ表示くらいでしょうから、どっちでも良いんですがね(笑)...

#> 最初の「lastModified の値」でも挙げたとおり、 ページの移動操作で基準日に戻るケースがあるようなので、 現在時刻の差し替え処理は lastModified の値を設定する前に行っているのでしょうね〜


referrer の値

IE3.02 では document.referrer の値はドキュメント自身の URL が返ってきます。

このため、例えばリンクされているドキュメントを制限したいとしても この値を利用すれば IE3.02 では全て制限されることになります。

また、IE4.01SP ではこの点は修正されているようですが、 ローカルファイルの場合・新しいウィンドウで開く場合などは設定されません。

その他には IE4,IE5 で、詳細が不明ですがリンクがないページが設定されることもあるようです。 (ひょっとして、これはセキュリティホールかもしれません。)


referrer の値 その2

document.referrer はリンクもとの URL ですが、 リンク以外から表示した場合などは何が設定されるでしょうか?

特に、NN では実に色々なもの( 時にはウザッたいもの )が設定されます。

形式内容
http:/...インターネット上のファイルからの参照
IE 等では URL の表記が間違っていても補完される場合がある
file:...ローカルファイルからの参照
bookmarksMac版 NN 4.06以降でブックマークから参照
[unknown origin]Win版 NN 4.7でブックマークから参照
mailbox:/...NN でメール内のリンクから参照
IMAP:/...NN でメール内のリンクから参照
about:<URL>NN でキャッシュ情報からの参照
wysiwyg://<keyword>/<URL>NN でキャッシュ情報からの参照?
<keyword> には数種類のパターンがある
  • link.msg.<nn>
  • index.<nn>
  • <nn>
<nn> は2桁の通番
Blocked by Norton どうやら Norton Personal Firewall にブロックされたらしい(笑)

このソフトを使ったことがないので詳細は不明だが、 CGI では HTTP_USER_AGENT もブロックされているようだ

アクセス解析として CGIで生成するイメージをページに貼付ける場合などでは注意が必要です。

#> これは JavaScript ネタじゃないですね f^^;


hash の値

IE3.02 では location.hash の値は設定されません。

#> ヒョットすると「最新の情報に更新」を実行するとページの先頭になるのは これが絡んでいるのかしら?


arguments の値

JavaScript1.1 で実装された arguments プロパティは可変引数の関数を実現する上で 必要な手段を提供する function のプロパティです。

また、 JavaScript1.1 の JavaScript Guide には

An array corresponding to elements of a function.

とあります。

そこで、ある関数内で

func(arguments)

とするとどのようになるでしょうか。

結果は NN3 では arguments の値は旨く渡りません。

これは、 arguments が配列( Array )のように振舞っているが、実際には Array ではないからです。

例えば、 arguments.toString() と array.toString() を実行してみれば arguments が Array ではないことがよくわかります。

array.toString() を NN3 で実行すると各要素を「,」カンマで繋げた文字列が 得られますが、 arguments.toString() を実行すると、その関数のコードが出力されます。f(^^;

つまり、func(arguments) を実行すると、func には呼出し元の関数のコードが渡されるため、動作しないのです。

NN4 では、 arguments は完全に Array と同じ動作になったようで、このようなことにはなりません。

え? IE はどうかって?
勿論、旨く動作しません! f(^^;;;
それどころか、 array.toString() すら [object Object] なんて言われます。

#> ひょっとすると IE3 では旨く動くかもしれませんが...

対処方法としては、最初に arguments を使用する関数内で内部のチャントした配列に移し変えて、 配列を下位の関数に渡すようにすることでしょうか。(T_T;


Form で送信するデータ

時々 Form を使用して CGI にデータを送信したりしますが、 IE4 では内部コードを UNICODE にしているためにいろいろなトラブルが発生します。

有名な例では escape/unescape メソッドが URL encode/decode ではなく UNICODE escape sequence を生成するようになったので CGI に送信するデータを JavaScript で生成すると苦労します。

JavaScript で生成しない場合でも、 window.open メソッドで生成したウィンドウに document.write メソッドで FORM 自体を書込むと、送信されるデータは URL encode でも UNICODE escape sequence でもないデータになります。( これ、一体なんだろう?)

回避方法として知られている(というか、調べてみた結果というか)方法は


Form の target指定の不思議

NN4 では Form で target指定をする場合、信じられない挙動があるようです。

#> あまりに基本的な問題なのに無意識に避けていたようで、最近まで気がつかなかった。 f(^^;

と、言うのは target 指定をしたウィンドウで JavaScript を使用して 日本語の文字列を出力( document.write や alert など )すると文字化けを起こすようです。

現象の詳細は以下のようなものです。

ってことで、どうやら通常の文字化けの現象ではなく、 単純に FORM で送信の際に開くウィンドウの生成時の処理抜けの問題のようです。

対策としては、FORM の submit時に、先に window.open してあげれば良いのですが、 IE4 の「名称付きウィンドウと target指定」の問題が絡みますので、 ブラウザの種類とバージョンのチェックが必要となります。

因みに、この現象が発生するブラウザは NN4.04 以降のようです。

#> 今頃気がついても、アタシの環境では確認できない... f(^^;

もし、あなたのブラウザが NN4 ならこちらで この現象を確認することができます。


イベントの発生順

Form で使用するテキストボックスには onBlur, onChange など複数のイベントが 登録できますが、複数の事象が発生した場合(例えば、入力中に submitボタンを操作するなど) のイベントの発生順はどうやらブラウザ依存のようです。 (論理的な構造をとっていれば、このような問題は発生しない気がするのですが...)

このために、複数のイベントが重なる可能性のあるハンドリング処理は思わぬ問題の元となります。 イベントハンドリングは Form内の各要素のみにするか、 onSubmit で一括して行うかに統一した方が良いようです。


イベントの発生順 その2

NN3 から NN4 の間(少なくとも 4.04 では確実)に BODY属性の( LAYER 絡みと類推 ) イベントのハンドリング方法が変わったようで、 この Tips集のように Frame 構成をとったページの親で定義した onUnload イベントが location.replace メソッド呼出し時に replace した後呼出されるケースがあるようです。

注 少なくとも最新版の NN4 では、この現象は発生していないようなので 修正されているのかもしれません

このような現象が出る可能性がある場合、関係ないとは思いつつ replace する前の ドキュメントで定義した onUnloadイベントに記述した関数と同じ名前の無処理の関数 をダミーとして定義しておくといいです。

ついでに、onLoad, onUnload メソッドの呼びだし順を調べてみると、 NN3 と IE4 では フレームの親子の関係は全くなく、 独立して( 非同期で )各 onLoad, onUnload メソッドが呼び出されます。

NN4 では、onLoad は子のフレームで onLoad イベントが発生し、 最後に親フレームの onLoad イベントが発生するようです( この仕様は良いかも ^^; )。

しかし、onUnload イベントに関しては親フレームが切替わるとき 子フレームの onUnload イベントが発生しません。

また、親フレームの onUnload イベント発生時に次のページを表示している場合があるようです。

前述の replace メソッドの問題は、この動作が影響しているようですが、 もし、この仮定が正しいとすると replace メソッドだけではなく、 いつでもタイミングにより同種の現象が発生すると思われます ( と言っても、最新版では修正されているような気もします ^^; )。


イベントの発生順 その3

少なくとも NN(IE は未調査)で Frame構成 のそれぞれのページに onUnload イベントを設定してみると、 どうやら onUnload イベントが呼出される前に実際 unload 状態になっているようで、 別のページから他のフレームの関数を呼出す場合に、 onUnload イベントを使用してそのページの関数が有効かどうかを制御しようとしたら 結局、onUnload イベントの処理が実行される前に既に該当の関数が未定義エラーになって しまいました。

できる限り別フレームの関数の使用は避けた方が良いようです。


他のウィンドウへのアクセス

ある方からメールで相談されて初めて知ったことなのですが、 IE( 少なくとも IE4,IE5 )でアイコン化されたウィンドウ内から他のウィンドウに対して 参照などのアクセスする時、アイコンメニューが表示されていると

アプリケーションが同期入力呼出しをディスパッチしているので、 送信呼出しは行えません。

と言われちゃいます。

#> これじゃぁ何のことか分かりませんよね〜 f(^^;

これは、通常あり得ないとお思いでしょうが、意外とあり得るスクリプトなのです。

つまり、メイン・サブのような複数ウィンドウ構成の場合で、 どちらかのウィンドウが閉じた場合に連動した操作が必要な場合には、 NN でウィンドウのクローズボタン操作で onUnload が呼出されない現象を補完するために 互いのウィンドウを時間監視すると、今度は IE でこの現象が発生するワケです。

#> あちら立てればこちら立たずの典型ですね〜

これを回避するためにはブラウザ判別して、NN で時間監視、IE で onUnload、 の2本立てにすることしか思いつきません。


ページの印刷

ブラウザで表示された文書を印刷するケースは、個人的にはあまり多くないものの、 全くない訳ではありません。

例えば

なんてのがあります。 f(^^;

然し、Webページ の中には何らかの理由でフレーム構成を壊したくないのか、 フレーム構成のページのフレーム部分のみを表示しようとすると JavaScript でチェックしていて、 強制的にフレーム構成にするページがあります。

if(top == window) location.replace(thisPageURL);

NN では、このような仕掛けを作ると「印刷するページがありません」などと 言われて印刷できません。

このような場合、わざわざ JavaScript をオフしないと印刷できないことになります。 JavaScript で 表示内容を生成していない限りは...

#> 昔の IE の印刷は結構ヒドかったけど、 最近は印刷のためにだけ IE を使用することもしばしです。 f(^^;


Java との連携

JavaScript1.1 の仕様から LiveConnect と呼ばれる Java との( Plugin も含まれますが ) 連携のための I/F があります。

さすがに NN は現在のところ完全に動作しているようですが、 NN は少なくとも Applet が JDK1.1 ベースでコンパイルされたものは 日本語が表示できません。

また、IE4.0 は文字列を返すものは動作しますが、その他のオブジェクト (例えば String 配列など)を返すものは扱うことができません(つまり、未定義値が返ります)。


パフォーマンス

Javaと異なり JavaScript は比較的パフォーマンスは良いと思いますが (グラフィック等の機能がなく、テキストの編集も比較的少ないので 悪いはずがないという意見もあります)、この点に関しては NN4.0 および IE4.0 は問題があると言わざるを得ません。

つまり、 NN4.0 については JavaScript の window.open メソッド等一部の機能を Java をベースにしているようで( もう少し正確に書くと、特権を必要とする操作 - ここでは 100×100以下の小さなウィンドウやスクリーンサイズ以上の大きなウィンドウの生成 - ではセキュリティチェックを行うために Java の機能を利用しているようです )、 JavaScript を実行しているのに「Starting Java...」と表示して 固まっているかの如く待たされます (NN4.03 は本当に固まる場合があるようですが...)。

これは、Javaの初期起動に極端に時間がかかるせいのようです。

#> まあ、その分 NN 起動時の負担が軽減されているので 痛し痒しといったところでしょうか。 f(^^;

予め Java を初期起動しておきたいなら、 一度 "Java Console"( Communicator メニュー → ツール )を選択すればOKですが...

また、IE4.0 については LiveConnect つまり Java との連携時に NN と同様、 固まっているかの如く待たされます。

これも理由は定かではありません。 このため、JavaScript のコーディングも この様なパフォーマンスの劣化を避ける必要が出る場合があります。


パフォーマンス その2

NN4 と IE4 の初期表示を見てみると、IE4 の方が早く表示されると思いませんか?

でも、だまされてはいけません。 これは、よくやるプログラミング上のテクニックで、 実際には内部処理を後回しにしているだけで、 表示完了迄の時間は見た目ほどではないのです。

確認するには、 IE4 でチョット複雑なページ (イメージや Table、 JavaScript などのあるページがいいです) を表示している間に、URLアドレスの入力をしようとすればわかります。 内部処理も完了するまでは、アドレス入力部分にフォーカスは移りません。


パフォーマンス その3

IE4 のパフォーマンスは、悪くても NN4 並だと思っていたんですが (だって、 Windows95 の OS も作っているメーカだもんネ)、 少なくとも アニメーションGIF のパフォーマンスは極端に悪いと思います。

このページに「DHTML」の Tips があるんですが、この中に同じファイルで同じサイズの アニメーションGIF を 24個貼付けたら NN の数倍の時間がかかって表示され、 CPU 占有率も 100% に跳ね上りました。

#> DHTML のオブジェクト構造もいいかげんだけど、 アニメーションGIF は昔からやってるんだし、昔の NN の例だってあるんだから、 ちゃんとしないと DHTML どころじゃないような気がする...


パフォーマンス その4

IE4 の DHTML の場合特に悪い。

これは、IE4 の実装の問題でオブジェクトモデルを 変更しない限り期待できないと思われます。

この件の詳細は「怪談! Cross Browser」の「DHTML のパフォーマンス」に 書いてあるのでここでは省略しますが、とにかく、 DHTML で多くのレイアを生成し、 レイアの移動や表示/非表示を切替えるとア然とします。

このサンプルは「DHTML 〜 応用サンプル 〜 仮想デスクトップ」を IE4 と NN4 でご覧になるとよく分かります。

#> 別に IE4 だからって遅くなるようには作ってませんのであしからず f(^^;


セキュリティ

JavaScript にはセキュリティホールが多く、とりわけ IE には更に多いと言われています。

例えば、私の知る限り公開されていないものに ( Windows95版で、セキュリティと呼んでいいのかわかりませんが ) window.open メソッドを使用して開いたウィンドウに直接 HTML を記述すると、 BASE URL が 「file:C\WINDOWS\SYSTEM」 になる問題があります。

もし、あなたの見ているブラウザが Windows用 IE3.02 なら ここクリックしてみて下さい。

「アドレス」が「C:\WINDOWS\SYSTEM\BLANK.HTM」になっていませんか?

つまり、このフォルダが基点のアドレスになっているのです。
通常、WINDOWSディレクトリには ReadMe.txt があるので「../ReadMe.txt」にリンク を貼るとそのファイルを覗くことができます。

これそのものはブラウザのマシンの資源をブラウザから見られるだけなので、 あえてセキュリティホールとは呼べないかもしれませんが、 サーバからの指示でこのリンク先を読取ることができれば立派なセキュリティホールに なるとは思いませんか?


二つの顔を持つJavaScript

JavaScript は 1.1 までは IE が NN の言語仕様とオブジェクトモデルを真似て 互換を保つことを中心に開発されたため殆ど同じでした。

その後、言語仕様の部分は、冒頭で述べた通り、 非営利団体ECMAに委ねられ、 ECMA-262「ECMAScript Language Specification」という 200ページ弱の仕様書として 規定されています。

しかし、ECMA-262 は JavaScrpt として知られている言語仕様とオブジェクトモデルの両方を 規定しているわけではありません。 この仕様で規定されている項目は JavaScript の文法と基本部分のオブジェクト (Netscape Devdge Online の JavaScript Reference では Core API と言っている)に関する部分でしかありません。

それ以外の部分は W3C により HTML4 と CSS1/2 をベースに DOM1/2 として規定されつつありますが、 それでも、残念ながら window, navigator と言ったブラウザに関連するオブジェクトまでは 規定されていないのが現状です。

また、現状のブラウザでは言語仕様/オブジェクトモデル共に、 これらの仕様を満足しているわけではありません。

注 これらの仕様は IE4, NN4 の開発後に公開されているため、 当然これらの仕様を満足できるものでもありません。
また、IE5 は DOM の仕様を除いて標準化仕様公開の後に公開されましたが、 仕様に合わせる時間がないのか、未だに準拠していない部分が多いです。

最近では NN6( Mozilla )の公開により、仕様に比較的準拠したブラウザが出現しましたが、 IE4/5, NN4/6 が混在する環境では、当分の間、2つどころか三つ巴の状況が続くと思われます。


その他のコマゴマとしたバグ

特に IE にはその他にコマゴマとしたバグが多いです。 ( NN4 は大まかなバグが多いんだけど... f(^^; ) その上、JScript のバージョン(ブラウザのバージョンではありません)毎に 正常動作するものとしないものがあり、 JavaScript のコード内ではどれに 該当するかは判断できません。 そのため、必要とあれば実際にブラウザで動作確認する必要があります。


2つのブラウザに対するJavaScriptの評価

2つのブラウザに対するJavaScriptの評価(独断です)
項目評価備考
IENN
性能×NN は特に write メソッドが極端に悪い
IE は アニメーションGIF が悪いし、DHTML に至っては最悪
機能×NN は CSSサポートが独自路線のママではね〜
IE は独自路線がキツイが、機能的には頑張っている(IE5)
品質××NNは○であって欲しかった
IE は実行すれば必ず再現する類のバグが多い Mac版に至っては製品レベルではない
バグに対する対応×どちらも良くないが、 IE は対応した筈のバグがバージョンアップで再発したりする
信頼度×NNの信頼度は安定(高い訳ではないが)しているが IE の方は落ちる一方 f(^^;
総合評価何も言いたくない m(..)m
 あくまでも JavaScript のみに対する評価なのでお間違えのないように

Copyright(c) 1997 - 2001 ShinSoft. All rights reserved.