【Javascript】JScript の条件付コンパイルを使う


前回の記事「【MovableType】Twitterのつぶやきをサイドバーに表示する」で使ったソースコードを見ると、次のような不可思議な構文が含まれている。

/*@cc_on
@if (@_win32 && @_jscript_version>4)

var minmax_elements;

(中略)

minmax_scanner= window.setInterval(minmax_scan, minmax_SCANDELAY);
window.attachEvent('onload', minmax_stop);

@end @*/

この不思議な“@”付きの構文は“条件付コンパイル”と呼ばれ、Javascript と JScript の間の数少ない差異の一つだ。これを使うとスクリプトを IE にだけ適用することができるので様々な方面で活用されている(そもそも、IE にだけ特別な処理が必要なことが諸悪の根源ではあるのだが。)

@cc_on ってなに? – Clouder::Blogger
http://blog.clouder.jp/archives/001005.html

一行で IE の JavaScript を高速化する方法 – IT戦記
http://d.hatena.ne.jp/amachang/20071010/1192012056

JavaScriptでIEかどうかをたったの1行で判別する方法:phpspot開発日誌
http://phpspot.org/blog/archives/2007/04/javascriptie1.html

条件付コンパイルについて、以下を参考(コピペ)にしつつまとめてみる(以下、JScript も Javascript も区別なく Javascript と記載する。紛らわしいもん。)

Conditional Compilation of JScript/ JavaScript in IE
http://www.javascriptkit.com/javatutors/conditionalcompile.shtml

開始と終了

Javascript において、コメントは /* コメント */ のように記述する。

/*
    これはコメントです。
*/

条件付コンパイルはこれを利用し、/*@cc_on ~ @*/ と記述する。IE 以外のブラウザでは単なるコメントにしか見えないようになっているわけだ。

/*@cc_on
    alert( "IE 使ってるね!" );
@*/

テストページを開く

条件分岐

いわゆる if 文が使える。(元ネタ

/*@cc_on
    @if ( @_jscript_version == 5.6 )
        var nurupo = "インターネッツは任せろー";
        alert( "やめて!" );
    @elif ( @_jscript_version == 5.8 )
        var nurupo = "……でもこれが IE8 だとしたら?";
        alert( "ふしぎ!抱いて!" );
    @else @*/
        alert( "このスクリプトは IE6 と IE8 にしか反応しません" );
    /*@end
@*/

テストページを開く

@if ~ @elif ~ @else ~ @end の組み合わせで使う。elseif でも elsif でもないので注意。

特別な変数

上記のスクリプトで使った @_jscript_version は IE(正確には JScript エンジン)によってあらかじめ定められた変数である。他にどんなものがあるか列挙してみる。

変数一覧
名前 意味
@_win32 Win32 の時に true。それ以外だと NaN
@_win16 Win16 の時に true。それ以外だと NaN
@_mac Mac 版 IE だと true。それ以外だと NaN
@_alpha DEC Alpha 版 IE だと true。それ以外だと NaN
@_x86 CPU のアーキテクチャが x86 ファミリーなら true。それ以外だと NaN
@_mc680x0 CPU のアーキテクチャが 680x0 ファミリーなら true。それ以外だと NaN
@_PowerPC CPU のアーキテクチャが PowerPC ファミリーなら true。それ以外だと NaN
@_jscript 常に true
@_jscript_build JScript エンジンのビルドナンバー。
@_jscript_version JScript のバージョン。
@_debug デバッグモードなら true。それ以外だと false
@_fast ファーストモードなら true。それ以外だと false

最後の 2 つは JScript.NET で使うもののようだ。実質、必要なのはブラウザの判定に使う @_jscript_version だけであろう。

@_jscript_version の値一覧
対応するソフトウェア
1.0 Internet Explorer 3.0
2.0 Internet Information Server 3.0
3.0 Internet Explorer 4.0
3.0 Internet Information Server 4.0
4.0 Visual Studio 6.0
5.0 Internet Explorer 5.0
5.1 Windows 2000
5.1 Internet Explorer 5.01
5.5 Internet Explorer 5.5
5.6 Internet Explorer 6.0
5.6 Windows XP(SP2 まで)
5.7 Internet Explorer 7.0
5.7 Windows XP SP3
5.7 Windows Vista
5.8 Internet Explorer 8.0
5.8 Windows 7

なんだか IE 以外のも混じってるけど気にしない。IE9 では 5.9 になるのかな?

ユーザー定義変数

@set @変数名 = 値”の書式で自由に変数を定義することもできる。

/*@cc_on
    @set @myvar = @_jscript_version
    alert( "JScript エンジンのバージョンは " + @myvar + " です。" );
@*/

テストページを開く

変数の比較には次の演算子が使える(優先順位順)。意味は Javascript のものと一緒だ。

  1. ! ~
  2. * / %
  3. + -
  4. << >> >>>
  5. < <= > >=
  6. == != === !==
  7. & ^ |
  8. && |

変数が未定義(NaN)であるかどうかは次のようにして判断できる。

/*@cc_on
    @if ( @myvar != @myvar )
        alert( "@myvar は NaN です!");
    @end
@*/

テストページを開く

自分自身と等しくないのは NaN だけなのだ。

応用編:XMLHttpRequest オブジェクトを得る

では、最後に実際の使用例を載せておく。Ajax に欠かせない XMLHttpRequest オブジェクト のインスタンスを作成するコードとしては、次のようなものが多く使われる。

function HttpRequest(url, parameters){
    var pageRequest = false // XHR
    if ( window.XMLHttpRequest ) // 最近の IE や Firefox その他
       pageRequest = new XMLHttpRequest()
    else if ( window.ActiveXObject ){ // 昔の IE
        try {
            pageRequest = new ActiveXObject( "Msxml2.XMLHTTP" )
        } catch ( e ) {
            try {
                pageRequest = new ActiveXObject( "Microsoft.XMLHTTP" )
            } catch ( e ) {}
        }
    }
    else
        return false
}

この try ~ catch 構文は IE4 で使えないためにエラーになってしまう。未だに IE4 を使っている人がいるかどうかは別にして、Javascript を使えるすべてのブラウザに対応可能なものを条件付コンパイルによって書くと次のようになるだろう。

function HttpRequest(url, parameters){
var pageRequest = false // XHR
/*@cc_on
    @if ( @_jscript_version >= 5 )
        try {
            pageRequest = new ActiveXObject( "Msxml2.XMLHTTP" )
        } catch ( e ) {
            try {
                pageRequest = new ActiveXObject( "Microsoft.XMLHTTP" )
            } catch ( e2 ) {
                pageRequest = false
            }
        }
    @end
@*/

if ( !pageRequest && typeof XMLHttpRequest != 'undefined' )
    pageRequest = new XMLHttpRequest()

コメントを残す