今回はJavascriptで簡単な電卓をつくってみる。
まず123 + 456という計算をするプログラムを考えてみよう。 これをJavascriptで実行するには answer = 123 + 456 ; として、answerをdocument.writeで書き出すか、適当なHTMLフォームの値に設定すればよいことはすぐに想像できる。
次に電卓として使用するごとに変わる部分を考えてみよう。 数値は計算ごとに変わるので、これらは変数に入っていることがのぞましい。 計算対象は二つを超えることはないので(例えば 1 + 2 + 3 は 1 + 2 = 3 と 3 + 3 = 6 の2回の計算とみれば計算ごとに使う数値は二つである)、数値をいれる変数は二つあれば足りることがわかる。
演算の種類はプログラム開発を簡単にするために、今回は四則演算に限ることにする。 そうすると4種類の計算ができればよく、電卓にある + や - のボタンは演算方法を変えるためにあると考えることができる。
これらのことを考えて以下のような手順で動作する電卓をHTMLとJavascriptでつくってみる。
まずHTMLで電卓のみかけをつくる。 電卓にあるボタンをinputタグで再現する。 これらのボタンもJavascriptの document.write で出力することもできるが、今回はレイアウトやプログラムをシンプルにすることを考え、HTMLを直接作成することにした。
<!DOCTYPE HTML>
<html lang='ja_JP'>
<head>
<style type='text/css'>
input{
font-size: large;
width: 40px;
height: 40px;
}
</style>
<script type='text/javascript'><!--
--></script>
</head>
<body>
<table>
<tr>
<td><input type='button' value='7'></td>
<td><input type='button' value='8'></td>
<td><input type='button' value='9'></td>
<td><input type='button' value='/'></td>
</tr>
<tr>
<td><input type='button' value='4'></td>
<td><input type='button' value='5'></td>
<td><input type='button' value='6'></td>
<td><input type='button' value='*'></td>
</tr>
<tr>
<td><input type='button' value='1'></td>
<td><input type='button' value='2'></td>
<td><input type='button' value='3'></td>
<td><input type='button' value='-'></td>
</tr>
<tr>
<td><input type='button' value='0'></td>
<td><input type='button' value='.'></td>
<td><input type='button' value='='></td>
<td><input type='button' value='+'></td>
</tr>
</table>
</body>
</html>
以後の解説では簡単にするために1行目のボタンだけ表示させる。
ボタンが押されたときにJavascriptを動作させるために、onclick属性と対応する関数をつくる。 いきなり全部につけるのは面倒なので、とりあえず1番上のボタンに設定する。
数字のボタンが押されたときにclickNumber関数を実行し、演算のボタンが押されたときにclickFunction関数を実行するようにした。
<!DOCTYPE HTML>
<html lang='ja_JP'>
<head>
<style type='text/css'>
input{
font-size: large;
width: 40px;
height: 40px;
}
</style>
<script type='text/javascript'><!--
function clickNumber(){
alert('数字が押された');
}
function clickFunction(){
alert('演算のボタンが押された');
}
--></script>
</head>
<body>
<table>
<tr>
<td><input type='button' value='7' onclick='clickNumber()'></td>
<td><input type='button' value='8' onclick='clickNumber()'></td>
<td><input type='button' value='9' onclick='clickNumber()'></td>
<td><input type='button' value='/' onclick='clickFunction()'></td>
</tr>
</table>
</body>
</html>
上記の例では7から9までのボタンのいずれにもclickNumber関数を設定した。 この場合、clickNumber関数の中ではいずれのボタンが押されたのかわからない。 そこで、clickNumber関数に押されたボタンを引数として渡すようにしてみる。 具体的には onclick='clickNumber()' となっているところを onclick='clickNumber(7)' のようにしてみる。 onclick属性の値はそのまま関数を実行する形になっていることを思い出そう。
clickNumber関数の定義も変更して、引数を受け取るようにする。
<!DOCTYPE HTML>
<html lang='ja_JP'>
<head>
<style type='text/css'>
input{
font-size: large;
width: 40px;
height: 40px;
}
</style>
<script type='text/javascript'><!--
function clickNumber(value){
alert(value + 'が押された');
}
function clickFunction(){
alert('演算のボタンが押された');
}
--></script>
</head>
<body>
<table>
<tr>
<td><input type='button' value='7' onclick='clickNumber(7)'></td>
<td><input type='button' value='8' onclick='clickNumber(8)'></td>
<td><input type='button' value='9' onclick='clickNumber(9)'></td>
<td><input type='button' value='/' onclick='clickFunction()'></td>
</tr>
</table>
</body>
</html>
clickNumber関数に引数を渡すことによって、どのボタンが押されたのかを関数が知ることができるようになった。 ただ、このやり方には問題がある。 数値入力のためののボタンは11個もあり、それらに個別に設定しなければならないことは面倒である (プログラマーは2回以上同じことをしてはいけない)。 そもそもボタンにはボタンを区別するためにすでに数字がvalueの値として割り当てられているので、onclickにも同じ値を設定するのは無駄と考えるようになってほしい。
押されたボタンを判別するにはボタンそのもの(inputタグ)を関数に渡すようにすればよく、そのために使われるのは this というキーワードである。 clickNumber関数を呼び出しているのはユーザーが押したボタンそのもので、thisは関数を呼び出したものを指す変数として使うことができる。
thisを受け取る関数側ではこれを引数にいれる。 引数にthisを使うことができないので、ここでは button とした。 clickNumber 関数内では変数 button が関数を呼び出したHTML要素として扱うことができる。 alert に変えて console.log 関数を使うことで、button の状態をより正確にみることができる(ウェブブラウザーの開発者ツールのConsoleを見る)。
<!DOCTYPE HTML>
<html lang='ja_JP'>
<head>
<style type='text/css'>
input{
font-size: large;
width: 40px;
height: 40px;
}
</style>
<script type='text/javascript'><!--
function clickNumber(button){
console.log(button);
}
function clickFunction(){
alert('演算のボタンが押された');
}
--></script>
</head>
<body>
<table>
<tr>
<td><input type='button' value='7' onclick='clickNumber(this)'></td>
<td><input type='button' value='8' onclick='clickNumber(this)'></td>
<td><input type='button' value='9' onclick='clickNumber(this)'></td>
<td><input type='button' value='/' onclick='clickFunction()'></td>
</tr>
</table>
</body>
</html>
Consoleに <input type='button' value='7' onclick='clickNumber(this)'> のように表示されることがわかる。 これはつまり、clickNumber関数の引数buttonがinputタグそのものになっていることを意味する。
電卓の計算結果を表示する部分をHTMLのフォームで表現する。 これは後でJavascriptから操作できる必要があるので、id属性をつけておく。 また <input type='text'> でつくると数字をいれたくなるので、readonly属性をつけて入力できないようにした。
clickNumber関数内ではbutton変数に押されたボタンが入っている。 ボタンの表示文字列はbutton.valueをすることで取得できる。 (難しい表現をするとHTMLオブジェクトのvalueプロパティということになるが、ここでは変数に.valueをつけることでそれが指すHTML要素のvalueの値を取得できると考えておけばよい)。
表示用のフォームに押されたボタンの値を追記させる。
<!DOCTYPE HTML>
<html lang='ja_JP'>
<head>
<style type='text/css'>
input{
font-size: large;
width: 40px;
height: 40px;
}
input#output {
width: 160px;
text-align: right;
}
</style>
<script type='text/javascript'><!--
function clickNumber(button){
// button.value に input タグの value 属性の値が入っている。
// 以下のようにすると押されたボタンの値をテキストボックスにいれることができる。
// document.getElementById('output').value = button.value;
// 数字は上位の桁からいれていくので、前の値に追加するようにする(ここの+は文字列をつなぐ演算子であることを思い出すこと。
document.getElementById('output').value = document.getElementById('output').value + button.value;
}
function clickFunction(){
alert('演算のボタンが押された');
}
--></script>
</head>
<body>
<table>
<tr>
<td colspan=4><input id='output' type='text' readonly='readonly'></td>
</tr>
<tr>
<td><input type='button' value='7' onclick='clickNumber(this)'></td>
<td><input type='button' value='8' onclick='clickNumber(this)'></td>
<td><input type='button' value='9' onclick='clickNumber(this)'></td>
<td><input type='button' value='/' onclick='clickFunction()'></td>
</tr>
</table>
</body>
</html>
演算ボタンが押されたときの動作は次のようになる。
<!DOCTYPE HTML>
<html lang='ja_JP'>
<head>
<style type='text/css'>
input{
font-size: large;
width: 40px;
height: 40px;
}
input#output {
width: 160px;
text-align: right;
}
</style>
<script type='text/javascript'><!--
var first, second, ope; // これらの変数はHTML全体で共有される。
function clickNumber(button){
document.getElementById('output').value = document.getElementById('output').value + button.value;
}
function clickFunction(button){
first = document.getElementById('output').value; // 変数 first は関数の外で定義済み。もしここで var first としてしまうと関数内でしか使うことができず、関数が呼び出されるごとに消えてしまうことに注意する。
document.getElementById('output').value = ''; // 二つ目の数値入力のために空にする(長さ0の文字をいれる)。
ope = button.value;
console.log(first, ope); // 変数の状態が変わっていることを確認する
}
--></script>
</head>
<body>
<table>
<tr>
<td colspan=4><input id='output' type='text' readonly='readonly'></td>
</tr>
<tr>
<td><input type='button' value='7' onclick='clickNumber(this)'></td>
<td><input type='button' value='8' onclick='clickNumber(this)'></td>
<td><input type='button' value='9' onclick='clickNumber(this)'></td>
<td><input type='button' value='/' onclick='clickFunction(this)'></td>
</tr>
</table>
</body>
</html>
=が押されたときにもclickFunction関数が呼ばれるようにする。 他の演算ボタンと違う動作をさせるために if で分岐させる。
<!DOCTYPE HTML>
<html lang='ja_JP'>
<head>
<style type='text/css'>
input{
font-size: large;
width: 40px;
height: 40px;
}
input#output {
width: 160px;
text-align: right;
}
</style>
<script type='text/javascript'><!--
var first, second, ope; // これらの変数はHTML全体で共有される。
function clickNumber(button){
document.getElementById('output').value = document.getElementById('output').value + button.value;
}
function clickFunction(button){
if('=' == button.value){
first = parseFloat(first); // この時点でfirstに入っているのは文字列。計算に使えるようにするために数値に変換する。
second = parseFloat(document.getElementById('output').value);
var answer;
if('+' == ope){
answer = first + second;
}else if('-' == ope){
answer = first - second;
}else if('*' == ope){
answer = first * second;
}else if('/' == ope){
answer = first / second;
}
console.log(answer, button);
document.getElementById('output').value = answer;
}else{
first = document.getElementById('output').value;
document.getElementById('output').value = '';
ope = button.value;
console.log(first, ope);
}
}
--></script>
</head>
<body>
<table>
<tr>
<td colspan=4><input id='output' type='text' readonly='readonly'></td>
</tr>
<tr>
<td><input type='button' value='7' onclick='clickNumber(this)'></td>
<td><input type='button' value='8' onclick='clickNumber(this)'></td>
<td><input type='button' value='9' onclick='clickNumber(this)'></td>
<td><input type='button' value='/' onclick='clickFunction(this)'></td>
</tr>
<tr>
<td><input type='button' value='4' onclick='clickNumber(this)'></td>
<td><input type='button' value='5' onclick='clickNumber(this)'></td>
<td><input type='button' value='6' onclick='clickNumber(this)'></td>
<td><input type='button' value='*' onclick='clickFunction(this)'></td>
</tr>
<tr>
<td><input type='button' value='1' onclick='clickNumber(this)'></td>
<td><input type='button' value='2' onclick='clickNumber(this)'></td>
<td><input type='button' value='3' onclick='clickNumber(this)'></td>
<td><input type='button' value='-' onclick='clickFunction(this)'></td>
</tr>
<tr>
<td><input type='button' value='0' onclick='clickNumber(this)'></td>
<td><input type='button' value='.' onclick='clickNumber(this)'></td>
<td><input type='button' value='=' onclick='clickFunction(this)'></td>
<td><input type='button' value='+' onclick='clickFunction(this)'></td>
</tr>
</table>
</body>
</html>
以下の問題を解決して電卓を完成させ、そのJavascriptを含むHTMLファイルを提出せよ。
小数点が入力されたかどうかを記録する変数 ten を用意して、数字入力のときの処理を変更する。
1.2.3 + 1.2 が 2.43 となるようにする。1.2.3 + 1.2.3 = 2.46 となることも確認する。
電卓を続けて使うことができない。
AC (all clear)ボタンをつけて、初期化する。
二つ目の数値の入力が始まるまで一つ目の数値の表示を消さないようにする。
演算ボタンが押されたときに、second_input 変数をtrueにする。 second_input が true のときに数値ボタンが押されるとoutputをクリアする。
3 = と入力するとエラーになってしまう。
ope が設定されていないときはsecondをそのままanswerにする。
ここまでプログラムを書いた時点で、document.getElementById('output')だらけになっていると思います。 これを変数にいれてみようと思います。
<script type='text/javascript'><!--
var first, second, ope;
var ten = false, second_input = false;
var output = document.getElementById('output');
--></script>
ところがこれではうまく動きません。 HTMLファイルは先頭から順に処理されていくので、Javascriptを実行する時点ではoutputのHTML要素が無いからです。 document.getElementById('output')を上手く働かせるためには<input id='output'>より後ろにJavascriptが出てこないといけません。 そのためにscriptタグ全体を後ろにもっていくと、今度はonclick属性に設定した関数の定義がinputタグの後に行ってしまい、inputタグを表示させるときに関数が無いという状態になります。
これの問題を解消するにはHTMLファイル全体がブラウザーに読み込まれた後にJavascriptを動かす必要があります。 そのために使うのが window.onload プロパティです。 このプロパティに設定するのは関数です。 設定された関数はHTMLファイルがブラウザーに読み込まれたあと(ロード後)に実行されます。 (ゲームを始めるときなどに Loading... と表示されることがあります。 これはプログラムをコンピュータのメモリに読み込んでいることを示しています。 ブラウザーもHTMLファイルをメモリにロードしているのです。) 以下のように使います。
// 初期化処理 (ACボタンのときにも使える)
function reset(){
output = document.getElementById('output');
}
window.onload = reset;
--></script>
今回は演算ボタンに*とか/を使っていますが、電卓の表示としては × と ÷ を使ったほうがよいでしょう。 これらの文字はHTMLのエンティティ文字と呼ばれ、特殊な表現を使うことで表記できます。 エンティティ文字一覧 ただこれらを使うとopeにいれてそのまま使うということができなくなるので、一工夫必要となります。
<input type='button' value='×'> <input type='button' value='÷'>