Wireless・のおと

JavaScript のはなし

ブログ
技術解説 昔話 HTTP

HTTP がらみで、今回は JavaScript の話です。無線の話からどんどん離れている?いえいえ、決して無縁ではないんですよという話も入ります。

JavaScript は HTML 文中に埋め込まれて実行されるスクリプト言語です。四の五の理屈を並べるより現物を示したほうが早いと思うので、簡単な例として HTML 電卓のソースコードを示します。
 

<html>
<head>
<script type="text/javascript">
<!--
function calc()
{
  document.f.v.value = eval(document.f.s.value);
}
-->
</script>
</head>
<body>
  <form name="f">
    <input type="text" name="s">
    <input type="button" value="=" onclick="calc()">
    <input type="text" name="v">
  </form>
</body>


JavaScript 電卓 HTML の例(実際に動作します)

この例ではボタンをクリックすると JavaScript の関数 calc() が呼び出され、フォーム "f" の文字列入力フィールド "s" の内容が eval() 関数に渡されて数式として演算され、その答えがテキスト "v" に書き戻される仕組みになっています。詳しくはネット上に沢山出ている JavaScript/HTML 入門を検索してください。

JavaScript のソースコードは <script>~</script> というタグによって囲まれます。その直後に付いている <!-- ~ --> は HTML のコメント文法で、<script> タグを解釈できない(JavaScript が実装されていない)ブラウザに読み飛ばさせて互換性を確保する(少なくともエラーにはさせない)ためのものですが、いまどき JavaScript が実装されていない HTML ブラウザなど殆ど無いので、いわば進化の過程で残された盲腸のようなものです。

クライアント・サーバ世界でのローカル処理

JavaScript は「クライアント・サイド・スクリプト」です。それがどういう事なのかを理解するためには、まず「クライアント・サーバ型処理(これも昔流行ったキーワードですね)」を理解する必要があります。
古典的な HTTP CGI では、クライアントはサーバから受け取ったデータ(HTML や JPEG)を表示するだけです。データの判定・加工・編集など、「表示する」以外全ての処理はサーバで行われます。上に書いた電卓プログラムも、CGI ならば SUBMIT ボタンを押すたびに HTTP POST リクエストがサーバに送られ、サーバ上で計算された結果が HTML 文として HTTP レスポンスで返され、それをブラウザが再表示する形になります。
 

<html>
<body>
  <form method="post" action="/cgi-bin/calc.cgi">
    <input type="text" name="s">
    <input type="submit" value="=">
    <input type="text" name="v">
  </form>
</body>


古典的 CGI 電卓 HTML の例
(実際には動作しません。WEB サーバ側に POST を受け取ってフォームを処理し、この形式の HTML に結果を埋め込んで返す calc.cgi を実装する必要があります)


しかし JavaScript を使えば、いちいちサーバに送らなくても済む程度の処理...たとえばフォームの送信前に未記入項目や入力範囲をチェックするとか、選択肢に応じてフィールドの入力可能・不可能の属性を変更するといった、GUI なら「できてあたりまえ」の事がサーバを介さずに実装できることになります。これによって未記入・誤記入のフォームがサーバーエラーを生じるようなトラブルを未然に防ぐことができ、結果として回線やサーバの負荷を下げることができます。後には Ajax などの「リッチクライアント」として使われることになる JavaScript ですが、当初は HTTP POST と組み合わせる文法チェッカーとしての能力が評価され普及のきっかけとなりました。

祝福なき誕生

さて、JavaScript も 90 年代インターネット普及期の立役者 Netscape Communications 社の落とし子です。ごく初期には LiveScript と呼ばれていたのですが、Sun, Oracle, Netscape 3社協業の「Java 戦略」に絡めて「JavaScript」に改名された経緯があります。この改名は純粋にマーケティング(イメージ宣伝戦略)上のもので、技術的に Java と JavaScript は殆ど無関係です。Java と JavaScript の文法は「似ていないこともない」程度でソース互換性は皆無であり、コード移植には全文書き換えが必要です。

「Script」が付かない方の Java は仮想マシンコードを用いるコンパイラ言語であり、90 年代後期に熱病のように流行ったキーワードでした。近い将来ほとんど全てのコンピュータ上で Java が稼動し、ほとんど全てのアプリケーションは Java で書かれてどんなコンピュータでも動作するようになり、「intel の i386 コード互換」や「Microsoft の Windows API」などの独占的権利は消滅する(かもしれない)と考えられていたのです。WEB の中に埋め込む動的コンテンツとしても Java で書かれた「アプレット」が標準になると考えられており、それが「来なかった未来」だったことはこのブログでも以前触れました。

さて「Script」が付くほうの JavaScript は当初、本家本元の Java が普及するまでの場つなぎのように思われていました。しかし、本家の Java はバージョンアップのたびクラス仕様や挙動がチョコチョコ変わったり、Microsoft と Sun の特許論争があったりして普及がもたつきます。折しもインターネットが爆発的に普及し、WEB サイト運用者が回線やサーバの負荷増大や苦情サポートの対処に悩まされていたとき、JavaScript は「今そこにあって」「すぐ使える」技術でした。また、Java アプレットを書くためにはかなり巨大な Java Development Kit (JDK) をインストールして Java コンパイラにかけねばならなかったのに対し、JavaScript はソースコードを書いてブラウザに読ませればすぐ動く手軽さも魅力でした。

ブラウザ戦争と WEB2.0

JavaScript の可能性を飛躍的に発展させたのは皮肉にも、Java 戦略においては不倶戴天の敵であったはずの Microsoft 社が 1996 年にリリースした Internet Explorer 3.0 (IE3.0) でした。IE3.0 は JavaScript の互換品である JScript を備え、JScript には「マウスやキーボードの操作に反応して手続きが実行される非同期呼び出し機能(イベント)」や「自分自身が含まれる HTML 文を操作する動的 HTML 生成機能(DOM)」という大胆な機能拡張が取り込まれましたが、これはその後の Ajax につながる道を示したものでした。
JScript の拡張機能は本家 Netscape 社の Navigator 4.0 に逆輸入されますが、文法や挙動の細部が異なる実装となって互換性問題を生じました。この後しばらく Netscape 社と Microsoft 社は熾烈な「ブラウザ戦争」を繰り広げ、バージョンアップの毎に HTML や JavaScript に独自拡張をガンガン放り込んで互換性問題で IT エンジニアを泣かせることになります。

インターネット発展期に多大な影響と貢献を及ぼした Netscape 社でしたが、1998 年アメリカ・オンライン社(AOL) に買収された後は戦略判断のミス・朝令暮改的な方針変更が相次ぎ、坂を転げ落ちるようにシェアを落としてゆきます。私も Navigator 2.0 以来の「Netscape 派」だったのですが、Netscape Communicator 4.5 のあまりの出来の悪さに愛想を尽かして IE に乗り換えてしまいました。あれほど隆盛を誇り、あれほどインターネットの発展に貢献した Netscape 製のブラウザは、2000 年頃にはほとんど市場影響力を持たなくなってしまいます。
このような形でブラウザ戦争が終息し、また HTML4.0 や ECMAScript など拡張仕様の明文化・規格化が進んだこともあって、2000 年を過ぎた頃には HTML / JavaScript 互換性問題は落ち付いてきました(※註)。この頃から従来の「リクエスト~リプライ」の枠組みに捉われない、より対話的(インタラクティブ)なインターフェースの実装が模索されるようになります。この流れは「リッチクライアント」とか「WEB2.0」とも呼ばれ、一時期は専用のプラグイン・モジュールを必要とする Shockwave Flash (後の Adobe Flash) が流行ったりもしましたが、2005 年に Jesse James Garrett によって発表された「Ajax」という単語が JavaScript を一躍時代の寵児に祭り上げることになります。

※註:「落ち着いた」というだけで、DOM やイベント処理における「IE 系 vs Mozilla 系」の方言の違いは残ったままになっています。ブラウザバージョンを判断し処理を切り分けて互換性を維持するための定石は一通り揃っていますが、「いつまでこんな事をやらなきゃならないんだ」という気にもなります。

AJAX

Ajax が何なのかを簡単に説明することは難しいです。Ajax じたいは「Asynchronous JavaScript + XML」の略とされていますが、例えば XML は必ずしも必須ではありません(より簡易なデータフォーマットの JSON を使った実装も少なくない)。
従来の WEB ページでは、「リンクをクリックする」「フォームに記入して投稿ボタンを押す」などユーザーの操作があり、その操作に応じてサーバへのリクエスト送信・サーバからの応答(レスポンス)・レスポンスの表示が交互に動作していました。リクエスト~レスポンスの間、画面には砂時計が表示されて画面は「固まり」、ユーザーはサーバ応答を待たされることになります。
これに対し、Ajax の代表例は Google 社の地図サービス「Google Map」です。画面を「摘まんで」スクロールするだけで画面の端から地図データが自動的にロードされ、まだ未表示領域が残っていてもお構いなしにスクロール・拡大・縮小操作ができることは御存知でしょう。
Ajax では JavaScript の非同期イベント機能を徹底的に利用し、マウスカーソルの動きや画面のスクロールに応じてサーバへのリクエストが発行されます。このリクエストも「非同期型」なので発行後も画面は「固まる」ことなく動き続け、レスポンスは到着次第逐次処理されることになります。これが Google Map が「固まらずに動き続ける」仕組みですが、その裏では JavaScript の非同期イベント機構と HTML の自動生成機能(DOM)が動いており、そういう複雑な動作を可能にするだけの OS 能力や CPU 性能やメモリ容量の向上、ブロードバンド普及による回線速度の向上という背景がありました。

現在ほとんどのブラウザには JavaScript が実装されており、JavaScript の実行時に動的コンパイラを通して実行効率を改善する JIT (Just In Time) が実装されているものも多いです。Java 戦略というお家の事情で Java という看板を背負わされた「醜いアヒルの子」JavaScript が、かつて Java アプレットが夢見た「OS やハードウェアに関わらず動作する」「双方向の動的 WEB コンテンツ」を実現しているのは何とも皮肉な話だと思います。

JavaScript の仲間たち

既に述べたように JavaScript は Java 言語のサブセットではなく、C 言語や Perl など幾つか既存の技術から生まれてきたものです。一方、JavaScript を土台として PHP や C# などの言語も生まれました。ここでは特に JavaScript と関係の深い Perl と PHP について取り上げます。

Perl

Perl の歴史は 1980 年代にまで遡る古いインタプリタ言語です。それまで Unix 上で処理の自動化に使われていた(というか今でも魔拡張を重ねながら使われている) BSH スクリプトよりも柔軟で強力なスクリプト言語として、sed や awk などの文字列処理ツールの文法を取り入れて開発されたもので、JavaScript を含む後のインタプリタ言語に多大な影響を与えました。
Perl は Linux サーバ上で稼動する CGI の記述言語として広く使われています。CGI は子プロセスとして動作する実行系なら BSH だろうがネイティブ・バイナリだろうが何でも良く、別に Perl で書かなければならない規則はないのですが、Perl 言語は CGI で多用される文字列処理(パターン検索・パターン置換・順序入れ換えなど)が簡単に実装できるうえ、JPEG や PNG のような画像データ処理まで含む豊富なライブラリが充実しているので CGI のデファクトスタンダードになっています。

PHP

PHP(Personal Home Page) は 90 年代、サーバ側スクリプト処理(サーバ・サイド・スクリプティング) の既述に特化した処理系として生まれたものです。データベースエンジンとの連携が強力で、Microsoft 社の WEB サーバ IIS (Internet Information Service) で採用されたこともあって Windows 系では広く使われています。
PHP は CGI 同様に「サーバ側での処理」を既述する仕組みですが、ソースコードは JavaScript のように HTML 文中への埋め込みになります(※註)。JavaScript, Perl, PHP の3つは文法だけでなく動作原理も似て非なる代物なので、IT 入門者の頭を悩ませること請け合いでしょう。

※註:ただし PHP は単体の言語処理系として実行させることもできるので、Perl の代わりに CGI として使うことも可能です。

古典的な CGI では「HTML を吐き出すプログラム」を書かなければならないので、単純な「足跡帳」や「掲示板」ならともかく、フレームや CSS の入り組んだ複雑なページを CGI で扱うのは大変です。このテーブルはこっち、このフレームはあっち、このフォームはこのルーチンの中という風に、HTML がバラバラに分解されてソースコードのあちこちに散らばるからです。HTML がマトモに出るようにするだけでも大変で、まして他人の組んだ CGI を変更修正するなど悪夢のような苦痛です。この点 PHP は HTML の枠組みありきで既述できるので大いに楽ができ、Microsoft IIS との親和性もあって商用サイトのサーバ側処理として多用されています。

Perl/CGI, PHP, JavaScript の違い

CGI ではサーバ上でプログラムが実行され、その結果生成された HTML 文がクライアントに送信されます。例えば「1+1」という計算式を実行する Perl CGI スクリプト(test.cgi)は次のようになります。冒頭にある「print "Content-type:...」は HTTP ヘッダの出力ですが、Content-Length: ヘッダが省略されていることに注意してください。「HTTP のはなし」でも触れましたが、Perl CGI の多くは Content-Length: を出力しません。これをそのまま流してコネクション切断するか、一旦キャッシュして Content-Length や Chunk ヘッダを付加してから流すかは CGI の呼び出し元たる HTTP サーバの実装と設定に依存します。
 

#!/bin/perl
print "Content-type: text/html\n\n";
print "<html><body>1+1=";
print 1+1;
print "</body></html>"


計算式「1+1」を処理する Perl CGI コードの例

クライアントが CGI を http://www.nowhere.com/~ys/cgi-bin/test.cgi のような URL で呼び出すと、test.cgi というファイルが返ってくるのではなく、test.cgi を実行した結果が返されます(※註)。

※註:この場合、WEB サーバ側では「cgi-bin/ 下への要求は CGI とみなし、ファイルを実行した結果を返す」という条件が設定されている必要があります。この設定が違っていると、CGI を要求しても Perl のソースコードが返ってきます。

上で示したように Perl CGI のコードは「HTML を出力する Perl プログラム」ですが、PHP のコードは下記(test.php)のように HTML 文に埋め込みます。
 

<html><body>
1+1=
<?php printf("%d", 1+1); ?>
</body></html>


計算式「1+1」を処理する PHP コードの例

このファイルを例えば test.php としておき、http://www.nowhere.com/~ys/test.php として呼び出すと、test.php というファイルが返ってくるのではなく、サーバ側で PHP 実行系に test.php を通した結果、<?php ~ ?> の中身がプログラムとして実行され置き換えられた HTML 文がクライアントに返されます(※註)。

※註:この場合も、WEB サーバ側では「.php の拡張子を持つファイルは PHP 処理系を通した結果を返す」という条件が設定されている必要があります。この設定が違っていると、<?php> が入ったままの HTML ソースが返ってきます。

さて JavaScript で機能的に同じ「1+1 の計算結果を表示する WEB ページ」を書くと、下のようになります(test.html)。
 

<html>
<body>
1+1=<span id="answer"></span>
<script type="text/javascript">
<!--
var doc;
doc = document.getElementById('answer');
doc.textContent=1+1;
-->
</script>
</body>
</html>

 

計算式「1+1」を処理する JavaScript コードの例

サーバは http://www.nowhere.com/~ys/test.html の要求に対し、test.html をファイルとしてそのまま送信します。受信したブラウザの側が <script> タグを検出し、<!-- ~ --> の中身をプログラムとして実行します。スクリプトの解釈と実行はクライアント(ブラウザ)で行われるので、Perl や PHP のように「サーバ側は○○の条件に一致した場合ファイルを●●とみなし~」という設定は必要ありません。
ソース中に document.ウンタラカンタラと書いてあるのは DOM の文法です。JavaScript には Perl や PHP の print 文に相当する機能がないため、自分自身が含まれる HTML 文書をオブジェクトとして扱い、そのオブジェクトの属性(ここでは "answer" という ID を持つエレメント・オブジェクト)を書き換えることで表示を行っています。

かくして、状況と用途に応じて JavaScript (ブラウザ上でのスクリプト処理)、CGI (比較的単純な HTML を扱うサーバ側処理)、PHP (複雑な HTML を扱うサーバ側処理) が使い分けられているわけですが、おかげで似て非なる文法の言語が3種類も並存する羽目になってしまいました。Perl と PHP の変数には $ を付けるけれど JavaScript 変数は $ 無しだとか、Perl の文字列一致判定は eq だけど JavaScript は == で PHP は strcmp() だとか、Perl の配列は @変数名だけど JavaScript と PHP は array クラスだとか、同じことをやるのにいちいち「流儀」が違うので、3者を混ぜて作業しているとブチ切れそうになってきます。せめて変数や配列の定義くらい共通化できなかったのかよ!と思いますが、もともと出自の異なる言語が結果的に WEB 上で混用されているだけですから仕方ないです。

JavaScript の未来

HTML5 仕様では、任意の描画ができる Canvas 機能を筆頭に JavaScript の大幅な機能拡張が行われました。Ajax が拓いてきた双方向・リアルタイム型の WEB サービスを更に推し進める格好です。これを受けて「もう専用 APP の時代は終わった」「HTML5 でアプリを書けば何処でも何でも動作する」などと騒いでいる人もいますが、かつての「Write once, run everywhere」の Java 騒動を見てきた身には「やれやれ、20 年経ってまた同じことを言い出しましたか」と醒めた気にしかなれません。
JavaScript の普及は確かにものすごく、一時期には「リッチクライアント」の華だった Adobe Flash の凋落ぶりには諸行無常・盛者必衰の感があります。Flash の対抗技術として開発された Microsoft Silverlight に至っては Microsoft 自身が手を引いてしまいました。しかし、だからと言って HTML5 + JavaScript が「機種別 APP という概念を過去のものにする」「OS・ハードウェアの垣根を超越する」聖杯となるかどうか私は懐疑的です。せいぜい生温かい目で見守りましょう。

JavaScript は組み込み世界にも手を伸ばしています。「組み込み制御機器に簡易なプログラミング機能を搭載したい」という要求は昔からあり、Tiny BASIC だの Forth だの Ruby だの色んな流派の雑多な処理系がごっちゃに使われていました。しかし WEB 世界での JavaScript の圧倒的ともいえる成功を背景に、組み込み機器の制御プログラミングも JavaScript でやっちゃおう、というプロジェクトがいくつか動きだしています。

その基本となるものは Node.js と呼ばれる JavaScript 実行環境です。これは JavaScript 言語の実行処理系(いわゆる JavaScript エンジン、Google の開発した V8 JavaScript Engine が多用されているらしい)を中心にサポートライブラリと API を整備し、「ブラウザの外」でも独立した言語系として動作できるようにしたものです。Node.js を使うことによりサーバ側の処理も JavaScript で書けるようになるので、今後は Perl や PHP を置き換えてゆくことになるかも知れません。
Node.js はもともと WEB サーバ上の実行系として開発されたものですが、これを組み込み制御に使おうという話が 2013 年くらいから盛り上がりつつあります。技術的な優位性というよりも、組み込み系よりも圧倒的に頭数の多い「IT 系エンジニア」を組み込み開発に回せるという点が注目されているようでもあります。

IoT.js は Samsung が開発している IoT 向け JavaScript ライブラリで、これは軽量 JavaScript 処理系である JerryScript とセットになっています。報道によればコードサイズは 200KByte 以下、消費 RAM 容量 64KByte 以下とされています。「IoT.js」という名前は一時期 Node.js から分離していた(しかも後でまた統合された) io.js と多少紛らわしいのですが、仕様的には Node.js のサブセットのような実装らしいです。

Kinoma は Marvell が開発している IoT 向け JavaScript ライブラリですが、元々「モバイル向けメディアプレイヤーフレームワーク」として開発されたもので歴史は古く 2002 年にまで遡ります。やはり軽量 JavaScript エンジンである Kinoma JS とセットで提供されており、2014 年には Marvell 社の SoC を積んだ「Kinoma Create」というリファレンス・デザインがクラウドファンド資金(IndiGogo)でリリースされたということで少々ニュースになりました。Kinoma JS と Node.js の間に直接の互換関係は無いようですが、「Node.js に慣れた技術者は容易に Kinoma JS を使いこなせる」とされています。


これらのプロジェクトは軒並み「JavaScript に慣れた IT エンジニアでも組み込み開発できる!」ことが特長として挙げられていますが、Z-80 のアセンブラ時代からやっている身としては「うーん」と思ってしまいます。ポインタ振り回してレジスタ叩いたり、インターバルタイマに関数ポインタフック仕掛けたりの「原始的で野蛮な」組み込みプログラミングって、そんなに難しいことなのかなぁ?そもそも、「その程度のこと」も理解してない奴に組み込みプログラミングをやらせようというのが無茶なんじゃない?とも思います。

まとめ

祝福なき誕生から WEB2.0 時代の寵児にのし上がった JavaScript は、動作原理の美しさや設計構想の優劣よりも「必要なとき、必要な機能を備えてそこにある」ものが普及し改良されて伝わってゆくという、技術史における適者生存進化論を実証するような存在です。そして全ての技術がそうであるかのように、いつかは不必要となって廃れてゆく運命にもあるのでしょう。
コンピュータ技術者として JavaScript や DOM や CGI を知っておくことは損になりませんが、しかし「これさえ知っておけば一生食いっぱぐれない」などとは、とても私には言えません。Adobe Flash の台頭と凋落に象徴されるように、技術の盛衰サイクルはますます早くなっています。しかし技術者にとって本当に必要なこと...読み、聞き、理解すること、事実と推測を分けて考え、推測に基づいて実験を行い、観察された事実から更に推測を深め次に行うべき目標を選択すること、それら一連の顛末を報告書(論文)としてまとめ第三者に伝えること...は何も変わっていません。それは(文系・理系に関わりなく)「科学」という論理体系の基本でもあります。
昨今「若者の理系離れ」とやらが問題とされ、その梃入れ政策として「理系」教育機関への重点政策などが伝え聞かれますが、私には「大学の専門学校化」のように聞こえます。JavaScript が書けます IIS の設定ができます、でも論文は読めません報告書は書けませんという「即戦力」人材をいくら増やしても、「ものづくり」の地力はかえって低下するんじゃないかと思うのは、説教めいた年寄りの愚痴なんでしょうかね。

製品のご購入・サービスカスタマイズ・資料請求など
お気軽にお問い合わせください