第18回
条件式と演算子~制御構造をさらに理解する

知ることとわかること

何かについて『知っている』ことと『わかっている(判っている、解っている)』こととは似ているようで違います。プログラミングできることと、実用的なプログラムを作れることも、また同じです。僕の経験を少し書きます。

学生のWeb開発プロジェクト

僕は芸術系の大学で教員をしています。とある出版社の方から、雑誌のファンサイトを立ち上げるので協力してくれと、依頼を受けました。僕の教え子の中には、自分でWebサイトを運営し、JavaScriptやFlashを使って自作(写真やイラスト)を公開している学生が結構います。

そこで僕は「うちの学生にサイトを作らせてみましょう。彼らの勉強にもなるし、出版社とのつながりもできるので好都合です」と答え、デザインセンスのいい女子学生とWebプログラミングに自信のある男子学生数名に声をかけ、チームを作りました。

JavaScriptを使えるという女の子にサイトの骨格をデザインさせ、プログラミングできる男の子に最終的な仕上げをさせる──という算段だったのですが、途中で暗礁に乗り上げました。

配列がわからない?!

女の子の作ったJavaScriptのページはうまく動きました。デザインもよかったのですが、上部に並んだ複数のタブをクリックしたときの振る舞いを少し変更して欲しいと頼みました。すると、彼女は「難しくてできない」と言います。そこで元のソースを少し手直しし、「タブの画像に固有の名前を付けているけれど、それを配列にすればインデックスの操作で移動先のページと簡単に連動させることができるよ」とアドバイスしました。

すると、彼女の返答は、なんと「配列って何ですか?」でした。聞いたところ彼女は、他のWebサイトなどに使われているJavaScriptのソースをコピーし、画像などの名前だけを適当に書き換えて使っているとのこと。彼女にとって「JavaScritが使える」とは「JavaScriptを使ったページを作れる」ということであって「言語を理解して使いこなす」ということとはちょっと違っていたようです。

仕方がないので、Webプログラミングに自信のある男の子に僕が少し手直ししたソースを渡し、「彼女には無理だったから、君たちで効率的なソースに書き換えてくれ」と頼みました。1か月経っても連絡がないので進捗を尋ねると、彼らは「先生、できませんでした。どこの何を配列にすればいいのかさっぱりわかりません」と答えました。

「プログラミングに自信がある」と豪語していた彼らでさえ、配列やループを使いこなせるレベルではなかったのです。

配列と繰り返し処理

彼らがつまずいたのは、次のようなところでした。3つの領域にそれぞれ3種類のタブを用意し、それぞれtab0、tab1、tab2と名前(シンボル名)を付けておきます。タブの画像を別途配列に格納するまでは、まぁOKです(リスト1)。

リスト1:3つのタブのOn/Off時の画像を1つの配列として確保したソース(JavaScript)
<SCRIPT language="javascript">
<!--
  var img = new Array();
  img[0] = new Image();  img[0].src = "img/design/icon_top1.jpg";
  img[1] = new Image();  img[1].src = "img/design/icon_top2.jpg";
  img[2] = new Image();  img[2].src = "img/design/icon_text1.jpg";
  img[3] = new Image();  img[3].src = "img/design/icon_text2.jpg";
  img[4] = new Image();  img[4].src = "img/design/icon_about1.jpg";
  img[5] = new Image();  img[5].src = "img/design/icon_about2.jpg";
                             :

タブにはマウスポインタが乗ったとき(MouseOverイベント)と外れたとき(MouseOutイベント)で画像を切り替えなければならないため、1つのタブにはOnとOffの2つの状況に対する画像が必要になります。リスト1ではimg[0]がトップページのOnの画像、img[1]がトップページのOffの画像……となっているため、すべてを一斉にOffにするような処理をfor文で記述するのに苦労します。

リスト2:3つのタブのOn/Off時の画像をそれぞれ異なる配列として確保したソース(JavaScript)
<SCRIPT language="javascript">
<!--
  var imgOff = new Array();    // Offの画像の配列
  var imgOn = new Array();     // Onの画像の配列

// Offの画像の配列を生成して初期化
  imgOff[0] = new Image();  imgOff[0].src = "img/design/icon_topOff.jpg";
  imgOff[1] = new Image();  imgOff[1].src = "img/design/icon_textOff.jpg";
  imgOff[2] = new Image();  imgOff[2].src = "img/design/icon_aboutOff.jpg";

// Onの画像の配列を生成して初期化
  imgOn[0] = new Image();  imgOn[0].src = "img/design/icon_topOn.jpg";
  imgOn[1] = new Image();  imgOn[1].src = "img/design/icon_textOn.jpg";
  imgOn[2] = new Image();  imgOn[2].src = "img/design/icon_aboutOn.jpg";

// 指定したタブをOnにする
function toOn(name, n)
{
  document.images[name].src = imgOn[n].src;
}

// 指定したタブをOffにする
function toOff(name, n)
{
  document.images[name].src = imgOff[n].src;
}

// すべてのタブを一斉にOffにする
// タブは'tab0'といった名前
function clear_images() {
  var i;
  for (i=0; i<3; i++) 
    toOff('tab'+i, i)
}
                             :

リスト2のようにOnの画像とOffの画像をそれぞれ別の配列とし、同じタブのOnとOffが同じ添字(インデックス)となるようにしていれば、特定のタブをOnにしたりOffにしたり、あるいはすべてを一斉にOffにしたりする処理を簡単に、わかりやすく記述できます。また、リスト3のように2次元配列とするのもひとつの手です。彼らにはこれを作るためのヒントを与えたのですが、理解できなかったのです。

リスト3:画像(Image)を2次元配列にしたソース(JavaScript)
<SCRIPT language="javascript">
<!--
  // 画像の配列 -- [種類,On or Off] -- 0がOff / 1がOn
  var imgOff = new Array(3,2);
// 画像の配列を生成して初期化
  img[0,0] = new Image();  img[0,0].src = "img/design/icon_topOff.jpg";
  img[0,1] = new Image();  img[0,1].src = "img/design/icon_textOn.jpg";
  img[1,0] = new Image();  img[1,0].src = "img/design/icon_textOff.jpg";
  img[1,1] = new Image();  img[1,1].src = "img/design/icon_textOn.jpg";
  img[2,0] = new Image();  img[2,0].src = "img/design/icon_abouytOff.jpg";
  img[2,1] = new Image();  img[2,1].src = "img/design/icon_aboutOn.jpg";

// 指定したタブをOnにする
function toOn(name, n)
{
  document.images[name].src = img[n,1].src;
}

// 指定したタブをOffにする
function toOff(name, n)
{
  document.images[name].src = img[n,0].src;
}

// すべてのタブを一斉にOffにする
function clear_images() {
  var i;
  for (i=0; i<3; i++) 
    toOff('tab'+i, i)
}
                             :

かなり簡略化しており、実際にはタブの数も多くて複雑なソースでした。だから余計にわかりにくかったのかもしれません。が、配列の添字をうまく使ってforで処理できるようにするなど、配列や繰り返し処理を理解していればちょっとした工夫で実現可能な仕組みです。

動く=完成……ではない

写真やデザインを学んでいても、さすがにプログラミングは学校で教えていません。授業でHTMLくらいは書けるようになっていても、論理的な『振る舞い』を記述するのは無理だったようです。

彼らが参考にしているWebプログラミングのソースも、必ずしも専門的な勉強をした人の手になるものではないでしょう。それをコピーして自分のサイトに使い、さらに別の誰かがまたそれをコピーして……と、合理的でないソースが連鎖的に広がることもあり得ます。

それでも、確かに『ちゃんと動く』ので、彼らとしては「うまくできた」ことになるのでしょう。プログラミングがどんどん楽になり、さらにJavaScriptのソースなどがWebで簡単に入手できるため、難しいことを知らなくてもプログラムを作れるようになってきました。それはそれで悪いことではないのですが、論理をソースに展開するというプログラミングの基本を押さえていない人が増えてきたのも事実です ※1

特にWebでは、デザインとプログラムの融合が重要課題となっています。Webはページのデザインが重視されますが、実際の『動き』を組み立てるのはプログラマーです。両者のスムーズな連携はなかなか実現しません。マイクロソフトのSilverlightも、そんな発想から生まれた製品のひとつです