この資料は2001年頃に作ったものを書き直したものです。HTMLタグに不慣れな方は「HTMLタグで作るマイページ」を参考にしてください。プログラミングの楽しさを味わっていただければ幸いです。本資料は Gentle Slope Systems(B.A.Myers) を意識しながら作成しました。
更新

例題で学ぶ JavaScriptプログラミング(入門編)

小山智史

(入門編)
1. 準備
2. JavaScript言語とプログラムの実行
3. 簡単なJavaScriptプログラム
4. データの型と変数
5. 演算
6. 入出力
7. 関数
8. 条件分岐: if文
9. 繰り返し: while文とfor文
10. 配列と連想配列
11. 関数: 再帰による関数定義
12. 文字列の処理と正規表現
13. 乱数の利用
付録A. JavaScript言語のまとめ

(応用編)
14. BMI早見表
15. 文書整形
16. 順序機械: 自動販売機
17. 教材分析
18. ゲームとパズル
19. 対話型学習ソフト
20. 統計処理

1. 準備

 デスクトップに jsprog というフォルダを作成してください。

 Windowsではデフォルトで拡張子が表示されないようになっています。フォルダの、[表示][オプション]の「表示タブ」で詳細設定の中の[登録されている拡張子は表示しない]のチェックをはずしてください。

 次に、jsprog フォルダの中に、メモ帳などのテキストエディタで以下の literacy.html というファイルを作成してください。

 プログラムをメモ帳で作成する場合は、[ファイル][名前を付けて保存]操作の後、ファイルの種類を「すべてのファイル」、「文字コード」を「UTF-8」にして保存します。

 テキストエディタ Mery で作成する場合は、[ファイル][名前を付けて保存]操作の後、ファイルの種類を「すべてのファイル」、エンコードを「UTF-8(BOM付き)」にして保存します。他の用途に差し支えなければ、[ツール][オプション]の[基本タブ]で、「既定のエンコード」を「UTF-8(BOM付き)」、「行番号を表示」をチェック、「タブの桁数」を「2」にし、[記号タブ]で、「改行表示」と「全角空白表示」をチェックしておくとよいかもしれません。

 literacy.htmlのアイコンをダブルクリックすると、Webブラウザが起動し、このページが表示されます。なお、本資料ではChromeブラウザで説明していますが、EdgeやFirefoxなど他のブラウザソフトでも構いません。


図1 HTMLファイルの編集とブラウザ表示

2. JavaScript言語とプログラムの実行

2.1 JavaScript言語

 プログラミング言語はコンピュータが理解できる特別な言葉です。プログラミング言語を使ってコンピュータにさせたい仕事を記述したものがプログラムです。プログラミング言語には多くの種類があり、目的によって使い分けられますが、ここでは、JavaScriptというプログラミング言語を用いてプログラムを作成します。

 Webページは、その記述言語であるHTMLで書かれています。その中に、HTMLとはまったく異なる言語であるJavaScript言語で書いたプログラムを埋め込むことにより、Webページの表示内容と関連したさまざまな処理を行うことができるようになります。

 Webブラウザは、HTML文書を解読して表示画面を作り上げるだけでなく、JavaScriptプログラムを解釈して実行する機能も持っているのです。

2.2 JavaScriptプログラムの実行

 literacy.htmlの末尾に以下のように3行を追加して保存してください。

 <script>と</script>のHTMLタグは、その間がJavaScriptプログラムであることを示していて、この例では「alert("Hello")」が「1行からなるJavaScriptプログラム」となっています。プログラムの内容は、「Helloとアラート表示しなさい」というものです。

 このページをブラウザで再読み込みすると、<script>と</script>のプログラムが実行され、下図のようなアラート表示が現れます。


図3 アラート表示(実行結果)

 alert(...) はJavaScript言語の命令語で、「ブラウザによってプログラムが正しく解釈されて実行された」というわけです。

(練習) プログラム中の「Hello」の部分を「こんにちは」に替えて、プログラムを実行してみなさい。

2.3 コメント

 プログラム中に「 / / 」が現れると、以後行末までコメントとなります。コメントはプログラムの実行に影響せず、プログラムの説明などを書きます。後から見直す時のために、次のように積極的にコメントを入れるようにします。

2.4 エラーとデバグ

 プログラムを作っても、意に反してうまく動作しないことはしばしばです。プログラムを作ったら、まずは思ったとおりにそのプログラムが動作しているかどうかを調べ、もしもうまく動作していなければ誤りを見つけて修正しなければなりません。

 ブラウザで、F12を押すとデバグウィンドウが現れ、プログラムに誤りがあった場合に、ここにエラー情報が表示されます。


図2 デバッグウィンドウ

 デバグウィンドウを別ウィンドウで表示するには、画面右下のを押し、を選びます。

 ここで、

のように、末尾の「 ) 」を取って(入力し忘れて)、ブラウザで再読み込みしてみてください。すると、文法エラーとなり、デバグウィンドウに誤りが指摘されます(図6)。ただし、いつも的確な表現で指摘してくれるとは限らないので、注意が必要です。


図6 デバグウィンドウのエラー表示

 プログラムが正しく動作しない場合は、誤りの箇所を探し、修正して再度動作を確認します。正しく動作するようになるまで

プログラムを修正し
上書き保存
プログラムを実行
(ブラウザで再読み込み)

を繰り返します。この作業はデバグと呼ばれます。「プログラムがうまく動作しないのは、そこに虫(バグ)が潜んでいるのが原因で、虫を退治(デバグ)すればプログラムが正しく動くようになる」というわけです。こう考えると幾分気が休まりますね。

(練習) プログラムを次のようにわざと間違えて実行してみなさい。

  1. 「script」を「sclipt」と間違う

  2. 字下げに全角スペースを使う

  3. 「alert(Hello)」のように「"」を忘れる

3. 簡単なJavascriptプログラム

 肥満の判定に用いられるBMI(Body Mass Index)は次式で計算します。ただし、単位は身長[cm]、体重[kg]。

この値は下表のように判定されます。

表2 BMI
19.8未満 19.8以上24.2未満 24.2以上26.4未満 26.4以上
やせ 普通 過体重 肥満

 ここで、身長が170cm、体重が65kgの人のBMIを計算するJavascriptプログラムは次のように書くことができます。

 このページを再読み込み(F5)すると、下図のようなアラート表示が現れます。


図4 BMI値のアラート表示

 プログラムは、初めに変数 h(身長)に 170 を代入し、次に変数 w(体重)に 65 を代入します。「 = 」は左辺と右辺が等しいということではなく、「右辺の値を左辺(の変数)に代入しなさい」という意味です。次に、h と w の値からBMIを計算し、変数 BMI に代入します。

 alert(BMI) で、BMI値をアラート表示します。

 <script> と </script> の間はJavaScript言語で表された「」の並びになっていて、文は「...しなさい」という命令を表しています。プログラムは文の並びで構成され、基本的には記述した順に実行され、このプログラムはフローチャートで表せば下図のようになります。


図5 順次実行

 文の末尾には「 ; (セミコロン)」を置きますが、省略しても構いません。ただし、1行に2つ以上の文を記述する場合は、「 h=170; w=65」のように、文の末尾(文と文の間)に「 ; 」を置きます。

 2.4でエラーとデバグについて書きましたが、文法エラーとは別の種類の誤りもあります。それは、BMIを計算する際に「10000」を「1000」と入力したような場合です。このような場合はコンピュータにとって誤りではなく、指示どおりに「正しく」計算し、その結果1桁違った結果が表示されることになります。このようなプログラム作成者の入力ミスや考え違いによって生じるエラーには特に注意が必要です。

(練習) プログラム中の「10000」の箇所を「1000」として、動作を確認しなさい。


4. データの型と変数

 変数はデータを入れる「箱」のことで、名前(変数名)が付けられます。宣言せずに突然変数を使いはじめることができ、0または空文字列("")に初期設定されます。変数名は、アルファベットで始まる英数文字列で、大文字と小文字は区別されます。大文字の変数名には、組み込み変数として使われているものもあるので、なるべく小文字を使います。

 「h=170」は、hという名前の変数に170という数値データを代入します。データの型には数値の他に、文字列論理値があり、変数にはどちらの型のデータも代入できます。他の多くのプログラミング言語では、あらかじめ変数の使用を宣言したりデータの型を指定する必要があります。数値は整数と浮動小数点数が区別なく扱われます。

 変数 s に文字列データを代入する場合は、

のように、文字列データの部分を「 " (二重引用符)」で囲みます。

 論理値は true (真)または false (偽)いずれかの値をとります。


5. 演算

5.1 算術演算

 「 BMI = w * 10000 / ( h * h ) 」は、h の値と w の値からBMIを計算して変数 BMI に代入します。乗算を示す「 * 」や除算を示す「/」を演算子といいます。

 「 5 + 10 」や「 x - y 」などはと呼ばれ、演算子に従って左右の値に対して演算が行なわれ、その演算結果が式の値となります。式を組み合わせた場合には、どの演算から順に計算されるかは演算子の優先度により決まります。優先して計算させたい箇所は、「 BMI = w * 10000 / ( h * h ) 」のように ( ) で括ります。 [ ] や { } などの括弧は利用できず、二重三重にする場合もすべて ( ) を使います。「 = 」は代入演算子です。

5.2 文字列の演算

 文字列の演算には連結演算(または連接演算)があります。二つの文字列をくっつけて一つの文字列にする演算で、演算子は加算と同じ「 + 」を使います。たとえば、「"標準" + "体重"」の演算結果は「"標準体重"」になります。次の例では、変数 z の値が「"標準体重"」という文字列になります。

 literacy.html を次のように変更して、動作を確認してください。

 変数 BMI には数値が代入されています。文字列と数値の「 + 」演算はないので、このような場合は、BMI の値を文字列に変換してから文字列の連結演算が行なわれ、「"BMIは22...."」のような文字列となり、表示されます。このように、データの型は必要に応じて「都合良く(ときには都合悪く)」自動的に変換されます。

 自動的な型変換は大変便利である反面、思わぬ落とし穴もあるので注意が必要です。変数 a のデータを明示的に型変換させるには、「 a * 1 」のように 1 を掛けて数値データにしたり、「 a + "" 」のように空文字列と連結演算を行って文字列にします。

5.3 比較演算

 数値の大小関係を調べるには、関係演算子を用います。「 h >= 180 」は身長( h )が 180 [cm]以上の場合に true(真)、そうでない場合は false(偽)になります。trueやfalseは論理値です。

 等しいかどうかを調べるには、「h == 180」のように「 == 」を用い、その値はtrue(真)またはfalse(偽)となります。「h = 180 」のようにすると h に 180 が代入され、式の値は 180 になってしまいます。

 関係演算子は文字列にも適用され、「 "ABC" == "ABC" 」「 "A" < "ABC" 」「 "A" < "B" 」などがtrue(真)となります。「 "10" < "2" 」もtrue(真)となるので注意が必要です。

(練習) h(身長)を 190 にして動作を確認しなさい。

(練習) w (体重)が 80 以上かどうか調べるようにし、w の値を変えて動作を確認しなさい。

5.4 論理演算

 論理式や論理値を組み合わせて複雑な条件を表現するには「 && (AND)」「 || (OR)」「 ! (NOT)」の論理演算子を用います。

 「 ( h >= 180 ) | | ( w >= 70 ) 」は、身長( h )が 180 [cm]以上かまたは体重( w )が 70 [kg]以上の場合に変数 big はtrue(真)、そうでない場合はfalse(偽)になります。

 実際にはこのように論理値をそのまま表示させることはなく、比較演算や論理演算は主に後出のif文やfor文の条件を表現する際に用います。

 論理演算の入力と出力の関係を表で表せば以下のようになり、これを真理値表といいます。

表3 論理演算
(AND)
xy x&&y
false(偽) false(偽) false(偽)
false(偽) true(真) false(偽)
true(真) false(偽) false(偽)
true(真) true(真) true(真)
(OR)
xy x||y
false(偽) false(偽) false(偽)
false(偽) true(真) true(真)
true(真) false(偽) true(真)
true(真) true(真) true(真)
(NOT)
x!x
false(偽) true(真)
true(真) false(偽)

(練習) h(身長)や w(体重)を変えて動作を確かめなさい。

(練習) h (身長)が180以上かつw (体重)が70以上の時に1が表示されるようにし、h や w の値を変えて動作を確認しなさい。


6. 入出力

6.1 アラート表示

 これまで使ってきた alert( ) です。表示内容はテキスト形式で書きます(改行は「¥n」)。

6.2 入力ダイアログ

 prompt( ) を使うと、入力ダイアログを表示し、ページを見ている人に何か入力してもらうことができます。

 以下は、身長と体重を入力してもらい、BMIをアラート表示します。

 prompt( ) は、引数として渡された「"身長?"」「"体重?"」などの文字列を小さなウィンドウに表示し、入力欄への文字入力を促します。入力欄に入力した値(文字列)は、prompt( ) の戻り値となり、h や w に代入されます。prompt( ) は文字列値を返すので、「 * 1 」で 1 を掛けることにより数値に変換しています。

(練習) BMIの正常値は、標準値22の±10%の範囲、つまり19.8以上24.2未満とされています。prompt( ) と alert( ) を使い、(1)身長を入力すると望ましい体重(BMIが22の時の体重)を表示するプログラムを作りなさい。(2)身長を入力すると「あなたの望ましい体重は○○~○○kgです」のように表示されるように変更しなさい。

6.3 ボタン操作

 以下は、ボタンが表示され、ボタンをクリックするとアラート表示が現れます。

 「 onclick=...」の部分は、ボタンをクリックしたときに...しなさいという意味です。

6.4 Webページ中に表示

 document.write( )を使うと、ページ中に表示できます。表示内容はHTMLタグを使って書きます(改行は「<br>」)。所定の表示をしておしまいという時に使います。一旦ページが表示された後に追加で表示させることはできないので注意が必要です。

6.5 表示内容の差し替え

 既に表示されているページの一部を差し替える場合は次のようにします。

 <div id=...>...</div>のように、あらかじめユニークな id (この例では "RESULT" )を付しておき、ボタン操作により RESULT を参照し、その innerHTML に「こんにちは」を代入することにより、表示内容を差し替えています。表示内容はHTMLタグを使って書きます(改行は「<br>」)。

  innerHTML で内容を差し替える他に、文字サイズや文字色や背景色を変更することもできます。画像を差し替えることもできます。

(例)

6.6 入力欄

 <input> は「1行の文字入力欄」で、<textarea></textarea> は「複数行の文字入力欄」です。どちらも、入力欄としてだけでなく出力欄としても利用できます。

 入力欄には、プログラムでその箇所を参照できるよう「 id=... 」のようにユニークなIDを付けます。

 以下の例では、FBMI というIDの入力欄を用意し、FBMI.value にBMI値を書き込んで表示します。

 身長や体重を入力すると以下のように入力欄にBMI値が表示されます。

 以下は、身長の入力欄( H )と体重の入力欄( W )を用意し、そこに入力された値を H.value と W.value で参照し、それらの値から計算したBMI値を入力欄 FBMI に表示できるように準備したものです(プログラムは次章)。

 以下のように表示されます(雰囲気だけです)。

6.7 音声の再生

 プログラムで録音音声を扱えると便利な場合があります。

 ページ中に音声を埋め込むには、あらかじめ音声ファイル(例えば hello.mp3 )を用意し、次のようにします。


7. 関数

7.1 組み込み関数の利用

 これまで、既に alert( )、document.write( )、prompt( ) などの関数を使ってきました。これらはJavaScript言語に予め用意されている関数で、組み込み関数と呼ばれます。

 以下のように、Math.round( ) という小数点以下で四捨五入する関数を使うと...のようになります。

 この場面では、小数点以下1桁まで表示させたいところです。以下のように「10倍した値を小数点以下で四捨五入し、その結果を10で割る」と...のようになります。

7.2 関数の定義と呼び出し

 組み込み関数と同じように使えるオリジナルの関数を作ることができます。以下では、bmicalc( ) という関数を新たに定義し、利用しています。

 「 function bmicalc( h, w ){ ... } 」では bmicalc という関数を定義し、「 BMI = bmicalc ( h , w ) 」でその関数を呼び出し、戻り値を利用しています。関数定義

のように書きます。引数の並びは「 , (カンマ)」で区切ります。引数が無い場合もあります。

 関数定義の{...}の中が複数の文からなる場合は順に実行され、{ ... } の中を最後まで実行するか、またはreturnが現れると、呼び出された箇所に戻ります。上の例のように、

を実行すると「値」を関数の値として戻ります。戻り値を必要としない場合もあります。

 <scriptp> と </script> の間のプログラムは書かれた順に実行されるのですが、関数定義の部分は例外で、その関数が呼び出されたときに実行されます。

 つまり、この例では、まず「 h=prompt("身長" , "") * 1 」と「 w = prompt("体重" , "") * 1 」が順に実行され、次に「 BMI = bmicalc( h , w ) 」で bmicalc( ) を呼び出します。そのときにhとwの値が引数として関数に渡され、それぞれ関数定義部分のhとwの変数に代入されます。bmicalc の関数では「 x = w * 10000 / ( h * h ) 」でBMI値が計算され x に代入されます。「 x = Math.round( x * 10 ) / 10 」で x の値が小数点以下1桁に修正され、return でその値が bmicalc( ) の戻り値となり、変数 BMI に代入されます。

 関数を定義することにより、プログラムの見通しが良くなります。また、この例では定義した関数を1度しか呼び出していませんが、関数を複数箇所で呼び出すような場合に関数の定義が効果を発揮します。なお、関数はそれを作る時点で役割が明確になっているので、後々のために上の例のようにコメントを記載しておくようにします。

 定義した関数が呼び出されることがなくても構いません。

 なお、「 var x 」は x を局所変数として宣言しています。これにより、変数 x はこの関数内でのみ有効となり、関数定義以外の箇所で同じ変数名 x を使っても、異なる変数として扱われます。「 var 」の宣言をしない場合は広域変数となり、この関数の外で同一の変数名を使った場合に、その値が書き換えられてしまう恐れがあります。関数内で一時的に使うことが明らかな変数は、var で宣言しておくことにより、ミスを未然に防ぐことができます。なお、関数定義の引数として用いられる変数は局所変数となります。

7.3 関数定義だけのプログラム

 6.3の例では、ボタンを押すとアラート表示が現れました。以下はこれを関数定義を使って書いたものです。

 プログラム部分は hello( ) という1個の関数定義のみで、ページを表示しただけでは何も実行されません。を押すと hello( ) という関数が呼び出され、「Hello」がアラート表示されます。このようなプログラムはイベント駆動型プログラムと呼ばれます(この場合はボタン操作がイベント)。

 以下は、身長や体重を入力欄に入力し(6.6)、ボタン操作でBMIを表示するようにしたものです。

 このプログラムはふたつの関数定義からなり、を押すと、bmi( ) が呼び出され、H や W の入力欄に入力されている値からBMIを計算し、BMI表示欄に表示します。

 以下のようになります。

(練習) フォーム入力と関数定義を使った異なる題材のプログラムを作りなさい。

7.4 ライブラリ


8. 条件分岐: if文

 BMI値が26.4以上の場合「肥満」と判断されます。literacy.htmlを次のように変更し、動作を確認してください。

if文は

と書き、式がtrue(真)の時に文が実行されます。この例では「 BMI > = 26.4 」がtrueの時に●付のBMI値が表示されます。フローチャートで表せば、一般には下図左、ここでの例に関しては同図右となります。


図7 条件分岐(1)

 しかし、このままでは、「 BMI > = 26.4 」がtrueでない場合には何も表示されません。その場合は●なしでBMI値だけを表示するには else を使い次のようにします。

 この場合のif文は

と書き、フローチャートで表せば、一般には下図左、ここでの例に関しては同図右のようになります。


図8 条件分岐(2)

 このように、条件によって処理の内容を変えることができます。もしも、ある条件を満たしたとき、あるいはそうでないときに、複数の文を実行させたい場合は次のようにします。

 上の例では、if文を使って2つの場合分けをしたわけですが、もっと細かく場合分けしたいこともあります。BMI値が26.4以上ならば●、24.2以上26.4未満ならば○、19.8以上24.2未満ならば◎、19.8未満ならば△をそれぞれ表示させてみましょう。●については既に正しく動作するので、「 x > = 26.4 」がfalseの場合について更に場合分けをします。if文を組み合わせて次のようにします。

フローチャートで表せば、下図のようになります。例えば「〇」の表示は、BMIが26.4未満24.2以上であることがわかります。


図9 複数の場合分け

 ここで、関数定義の復習になりますが、BMIの値に応じた記号を返す関数 mark( ) を定義し、次のようにしてみます。関数定義を使って機能を独立させることにより、プログラムの見通しが良くなります。

(練習) 身長や体重の入力欄が空( "" )の時に値の入力を促すアラート表示が現れるようにしなさい。

(練習) ●○◎△の記号ではなく、コメント欄にメッセージを表示するようにしなさい。なお、文字列の途中で改行させたい場合は「¥n」を使います。


9. 繰り返し: while文とfor文

9.1 while文

 以下は、はじめに身長を入力し、その身長に対するBMIの値を体重5kgきざみで計算して表示するプログラムです。

 while文

と書き、( ) 内の「式」がtrue(真)である限り何度でも、「文」を繰り返し実行します。フローチャートで表せば、一般には下図左、ここでの例に関しては同図右のようになります。


図10 繰り返し(while文)

 初めに w を 40 にしています。そして、「 w < = 80 」がtrue(真)である限り { } 内を繰り返し実行します。{ } 内の最後で w の値を 5 ずつ増やしているので、w はいずれ 85 になり、その時点で条件を満たさなくなり、繰り返しを終了します。

9.2 for文

 上の例のように、繰り返しのプログラムでは、初期化( w = 40 )と条件調べ( w < = 80 )と更新( w = w + 5 ) の3点セットが頻繁に登場します。この部分をまとめて書くようにしたのがfor文です。上の例はfor文を使って次のように書くことができます。動作は同じです。

 for文

と書き、はじめに「式1」を実行し、「式2」がtrue(真)である限り何度でも、「文」を実行しては「式3」を実行します。フローチャートで表せば、一般には下図左、ここでの例に関しては同図右のようになります。


図11 繰り返し(for文)

(練習) 正の整数を入力し、1からその値まで足した値を表示するプログラムをつくりなさい。

(練習) 半径に対する面積と体積の表を作りなさい。


10. 配列と連想配列

10.1 配列

 5人の横綱の身長が、変数 h1 ~ h5 に用意されている時に、平均身長 mh を求めて表示するプログラムは以下のようになります。

 では、5人ではなくて100人だとどうでしょうか。h1~h100に値が用意されていたとしても、それらは別々の変数なので、その平均を求めるためには以下のようにすべての変数名を明記しないといけません。

これは現実的ではありません。

 このように、データ数が多い場合は変数の一種である配列を使います。配列の場合、ひとつの変数に複数のデータを格納できます。

のように値を代入すると、1番目のデータ 178 は h[0]、2番目のデータ 177 は h[1] で参照できます。[ ] 内の番号を添え字(index)といいます。添え字は0から始まることに注意してください。

のようにまとめて代入することもできます。

 配列を使うと、順番にデータを扱うことが可能になり、for文で添え字( i )を変化させ、次のように平均身長を求めることができます。今の場合、i は 0 から 4 まで変化します。

 100人分のデータであったとしても(それをどうやって用意するかは別にして)、プログラムは5を100に替えるだけですみます。

 上の例では、5人の横綱の身長だけを扱いましたが、5人の横綱の「名前, 出身地, 身長, 体重」のデータを扱いたい場合はどうしたらいいでしょうか。このような場合は以下のように2次元配列を使います。

のように配列データを作ると、sumo[0] の値は [栃錦,東京都,178,127] という配列になり、栃錦の身長 178 はその3番目の要素なので sumo[0][2] で参照できます。

 なお、上のように配列が用意されている場合、そのサイズ(要素数)は sumo.length で参照でき、この例では 5 になります。また、sumo[0].length は 4 になります。

 この場合、横綱の平均身長を求めて表示するプログラムは以下のようになります。プログラム中のデータ数の箇所を「5」ではなく sumo.length にしたのは、こうしておくと今後データが追加された場合もプログラムを変更せずにすむからです。

(データファイルの分離)

 上記のような2次元配列で、歴代横綱の名前、出身地、身長、体重のデータを sumo.js というファイルに用意しました。こちらからダウンロードしてください(ダウンロード後に sumo.js.txt → sumo.js に名前を変更のこと)。テキストエディタで sumo.js を開いて確認してください。このファイルは literacy.html と同じフォルダに入れ、次のように利用します。

 以下は、すべての横綱についてBMIを計算して表示するプログラムです。

(CSVデータの出力)

 JavaScriptはファイルに出力することはできませんが、テキストエリアに出力したいデータを表示し、これをコピー&ペーストの操作で表計算ソフトなどに渡すことは可能です。

(CSVデータの入力)

 上記とは逆に、テキストエリアにコピー&ペーストの操作で貼りつけたCSVデータを受け取ることも可能です。

 split( ) で文字列を分解しています(12.1参照)。配列 rows には、rows[0]="栃錦,東京都,178,127" のようにテキスト入力欄( CSVDATA )の値を改行(¥n)で分割した1行分(1人分)のデータが入ります。これをまた「" , "」で分割すると、sumo.jsと同様の rows[0]=["栃錦","東京都",178,127] のような2次元配列のデータが得られます。

10.2 連想配列

 配列の添え字は0~の番号でしたが、添え字を文字列で扱うのが連想配列です。

 横綱の体重データを

のように用意すると、栃錦の体重127は w["栃錦"] で参照できます。

のようにまとめて代入することもできます。

 w={...} のように括弧の形が [...] ではないので注意してください。

 以下の例では、はじめのfor文で sumo.js のデータを読んで連想配列 w を作ります。そして、次のfor文「 for(name in w) 」で連想配列 w の添え字がひとつずつ name に代入され、document.write が繰り返されます。ただし、取り出す順番は定まっていません。

 以下は、すべてのデータを表示するのではなく、名前を入力するとその横綱の体重を表示するようにしたものです。

 while(true){...} の箇所は、{ } の中の処理を何度でも繰り返します。prompt( ) で入力した文字列が変数 name に入ります。次に、入力した文字列が空文字列の時(改行のみ行った場合)に break で while(){ } から抜け出ます。通常は、入力した名前がデータにあるかを if(name in w) で調べ、あれば名前と体重をアラート表示し、なければ「ありません」を表示します。

 以下は、連想配列を使って出身地別の人数を数えて表示するプログラムです。

 はじめのfor文で、配列 sumo のすべての横綱について、その出身地を添え字とする連想配列 ninzu の値に 1 を加えます。全レコードを読み終わった時点で、ninzu["青森県"] は 5、ninzu["長崎県"] は 1、...になっています。

 そして、次のfor文で、ken に連想配列 ninzu の添字がひとつずつ代入され、document.write が繰り返されます。

 データを読んでみないとどのような出身地が現れるかわからないわけですが、うまく処理することができます。


11. 関数: 再帰による関数定義

 前項で、出身地別に人数を表示することができましたが、これを簡易棒グラフで表示してみましょう。人数分だけ横に*印を並べることにします。プログラムは次のようにします。

 定義した関数 rep(a , n) は a という文字列を n 個繰り返した文字列を返すようになっています。rep("A",4)は "AAAA"、rep("AB",3) は "ABABAB" を返します。

 rep() の関数定義の中では while 文を用いて a を n 個連結した文字列 s を作成し、関数の値として返しています。

 rep() の関数定義を、次のように再帰による関数定義に書き換えてみましょう。

これは、rep("A",4) として呼び出された場合、rep("A",3) と "A" を連結した文字列を返せばよいと考えるものです。関数定義の中で定義途中の自分自身を呼び出していて、このように考えることにより問題を単純化できる場合があります。

 大きな問題をより簡単な問題の組み合わせに分解する考え方は分割統治と呼ばれ、再帰によって実現されます。別の例として、応用編の「ハノイの塔」があります。


12. 文字列の処理と正規表現

 文字列 "青森県" の文字数は 「 "青森県".length 」で参照でき、値は 3 となります。

 "This".toupper() は "THIS" になり、"This".tolower() は "this" になります。

 これまで取り上げた関数は「( )」の中に引数として値を渡してきましたが、ここで扱う関数は、「 "This".toupper() 」のように値を渡し、このような関数はメソッドと呼ばれます。「 "This" に対して toupper() の操作をする」と考えるといいかもしれません。

12.1 文字列の分割

 「2022/3/13」のような文字列があった時に、これを区切り文字「/」で分割するには次のようにします。結果は配列(この例では a )になります。

12.2 文字列の検索

 sumo.js から「青森県出身者」のデータを抽出してみます。

 次のようにしても結果は同じになります。

 ここで、「 〇〇.match(/ /) 」は「〇〇が「 / / 」で表されるような文字列パターンにマッチしていれば...」と読みます。「 / / 」で囲まれた部分は「正規表現」と呼ばれます。

 上の例は、「出身地に『青森県』という文字列が含まれている横綱を表示しなさい」という意味で、もしも出身地が「青森県弘前市」や「日本国青森県中津軽郡」のようなデータがあれば、それも表示されます。

 正規表現を使うと、複雑な文字列パターンを簡潔に表現することができます。

下記は「名前の最後の文字が『山』であれば...」です。「 /山$/ 」の「 $ 」は「文字列の最後」を意味します。

 下記は「名前の先頭文字が『北』であれば...」です。「 /^北/ 」の「 ^ 」は「文字列の先頭」を意味します。

 少し複雑な例として、下記は「名前が『のノ乃』のいずれかを含み、そのあと何か1文字で終われば...」です。[ ] は、その中のどれか1文字、「 . 」は「任意の1文字」を表します。

 下記は、「名前が3文字で2文字目が『の』の人であれば...」です。

(練習) 名前が「海」または「山」で終わる横綱を表示しなさい。

(練習) 北海道出身で名前のどこかに「北」がつく横綱を表示しなさい。

12.3 文字列の置換

 「 文字列.replace(r,s) 」は文字列の中の r を s に置き換える関数(メソッド)です。「 "本当ですか".replace(/本当/g,"ホンマ") 」は「ホンマですか」という文字列になります。正規表現「 / /g 」の「 g 」は、文字列中に「本当」が複数個あった時に全部置き換える指示です(gが無いとはじめの1個)。

 以下の例では、ふたつの置き換え(replace)を連続して行っています。このように最初の置き換えの結果に対して更に置き換えをするような書き方ができるのが、メソッドの特徴のひとつです。

 上記の置き換えを拡張したものがこちらの本格的な(??)翻訳プログラムです。

(練習) replace() を使い、「ですます体」の文書を「である体」に変換する整形プログラムを作りなさい。また、このプログラムで不都合が生じる例がないか考えてみなさい。

(練習) 上記を参考に、日本語文章をあなたの出身地の方言に変換するプログラムを作りなさい。


13. 乱数の利用

 組み込み関数 Math.random() は0~1の一様乱数を返します(下図左 x = Math.random() )。


図 一様分布(左)と生起確率のコントロール(右)

 以下は、Math.random() で生成した10個の乱数を表示します。

 プログラムで何かの生起確率をコントロールしたい場合、例えば「確率0.4である表示をしたい」とすれば、Math.random() の値が0~1の間の0.4の幅に入っている場合に(上図では0.2~0.6)、その表示をするようにします。

 以下は「おみくじ」のプログラムです。Math.random() の値が 0.9~1 の時に「大吉」(確率0.1)、0.6~0.9 の時に「吉」(確率0.3)、0.2~0.6 の時に「小吉」(確率0.4)、0~0.2 の時に「凶」(確率0.2)としています。

 以下はsumo.jsの中の横綱1名をランダムに抽出するものです。

 当選者を5名とするにはどうしたらいいでしょうか。ENDの中の処理を5回繰り返せばいいと考えるかもしれませんが、そうすると重複の可能性が出てきます。

 ライブラリ lib.js には、shuffle() が定義されています。この関数は、配列の要素をランダムに入れ換えます(Bentley:``Programming Pearls'' 11.3)。以下はこの関数を使って、sumo.js の中から5人の名前を抽出するプログラムです。配列をランダムに入れ換えた後、先頭から5人を当選者とします。

(練習) 「おみくじ」の確率を変えて実行してみなさい。また、「末吉」を追加してみなさい。


付録A. JavaScript言語のまとめ

□ JavaScriptプログラム

文の並び
関数定義
コメント // から行末まで、または /*...*/ で囲まれた部分

□ 文

制御文 if文、for文など
x=0, 関数呼び出しなど
{文の並び}

□ 制御文

if(式) 文 式がtrueならば文を実行
if(式) 文1 else 文2式がtrueならば文1、そうでなければ文2を実行
while(式) 文 式がtrueである限り文を繰り返し実行
for(式1;式2;式3) 文はじめに式1を実行し、式2がtrueである限り文を実行しては式3を実行
break forまたはwhileループから抜け出す
continue forまたはwhileのそれ以降の処理を飛ばして次のループへ
for...in forループ
eval JavaScript構文で記述された文字列を評価

□ 式

定数 数値定数または文字列定数
変数 数値か文字列
関数呼び出し
配列要素
(式) 優先する演算の明示
演算子で式を結合したもの

□ 演算子

(代入演算子)
x=y xにyの値を代入
x++ xの値を+1する
x-- xの値を-1する
++x xに1を足してから値を返す
--x xから1を引いてから値を返す
x+=y xにx+yの値を代入
x-=y xにx-yの値を代入
x*=y xにx*yの値を代入
x/=y xにx/yの値を代入
x%=y xにx%yの値を代入
(算術演算子)
x+y 加算
x-y 減算
x*y 乗算
x/y 除算
x%y xをyで割った剰余
+ x (単項)算術演算子
- x (単項)算術演算子
(文字列の演算)
x+y文字列xと文字列yの連結演算(または連接演算)
(関係演算子)
x==y xとyが等しければtrue,そうでなければfalse
x!=y xとyが等しくなければtrue,そうでなければfalse
x > y x > yならばtrue,そうでなければfalse
x < y x < yならばtrue,そうでなければfalse
x > =yx > =yならばtrue,そうでなければfalse
x < =yx < =yならばtrue,そうでなければfalse
(論理演算子)
x && y 論理積 AND: xがtrueかつyがtrueならtrue, そうでなければfalse
x || y 論理和 OR: xがtrueまたはyがtrueならtrue, そうでなければfalse
! x 否定 NOT: xがfalseならtrue, そうでなければfalse
(条件式演算子)
式1 ? 式2 : 式3式1が1(真)なら式2、そうでなければ式3

□ 入出力関数

alert(s) 小さなウィンドウを開き、sを表示
prompt(s,t) 小さなウィンドウを開き、sを表示し、キー入力した文字列を返す。tは入力文字の初期値
document.write(s)ブラウザ画面にsを表示

□ 算術定数

Math.E2.71828...(自然対数の底e)
Math.LN2ln 2
Math.LN10ln 10
Math.LOG2Elog2e
Math.LOG10Elog10e
Math.PI3.1415...(円周率π)
Math.SQRT1_2√1/2
Math.SQRT2√2

□ 算術関数

Math.sin(x)xの正弦
Math.cos(x)xの余弦
Math.tan(x)xの正接
Math.asin(x)範囲[-π/2,π/2], x in [ -1, 1 ] の sin-1(x)
Math.acos(x)範囲[-π,π], x in [-1,1] の cos-1(x)
Math.atan(x)範囲[-π/2,π/2] の tan-1(x)
Math.atan2(x)範囲[-π,π] の tan-1(y/x)
Math.exp(x)指数関数 ex
Math.log(x)自然対数 logex, x>0
Math.max(x,y)xとyの大きい方の値
Math.min(x,y)xとyの小さい方の値
Math.pow(x,y)xy
Math.sqrt(x)√x
Math.round(x)xを四捨五入
Math.ceil(x)xを切り上げ(xより小さくない最小の整数)
Math.floor(x)xを切り捨て(xより大きくない最大の整数)
Math.abs(x)xの絶対値
Math.random()0~1の一様乱数

□ 関数の定義

function 関数名(引数の並び){...}関数定義
return 関数から戻る
return 値 関数から戻り、値を返す
return 式 関数から戻り、式を値として返す

□ 局所変数の宣言

var局所変数の宣言

□ 正規表現

A Aそのもの(以下の特殊文字を除く普通の文字)
¥¥ ¥そのもの
¥" "そのもの
¥t タブ
¥n 改行
¥f フォームフィード
¥b バックスペース
¥033 8進数033
^a 文字列の先頭がa
a$ 文字列の末尾がa
. 任意の1文字
[abc] abcのどれか1文字
[^abc] abc以外の1文字
[a-e] abcdeのどれか1文字
[^a-e] abcde以外の1文字
a* 0個以上のaの並び
a+ 1個以上のaの並び
a? aが1個あるいは0個
abc|de abcまたは「de」

koyama88@cameo.plala.or.jp