<html> |
電卓用に「calc.html」を作成して、保存します。 |
<html> |
【電卓用のテーブルを作成】 まず、基盤となるテーブルを作成します。
|
<html> |
【ボタンを配置する】 次にボタンを全ての枠に入れておきます。 1つ作って、あとはコピーすれば楽ですね。
|
(省略) <form name="calc"> (省略)
|
【ボタンに文字を入れる】 ボタンに数字や計算の記号を書きます。
|
(省略) <form name="calc"> (省略) |
【計算結果の表示】 次に計算結果を表示する部分を作りましょう。 1つ目は計算結果の数字を表示する部分です。 2つ目は、計算の種類(記号)を表示するのに使います。数字の入力が終わったときにどんな計算が行われるか表示しています。 |
【電卓の特徴を考える】
スクリプトを書く前に、電卓の特徴を考えてみましょう。
使い方の基本は、数字→記号→数字→記号と、数字と記号の入力が交互に行われます。
数字は1つではなく複数のキーを連続で押し、記号が入力されると1つの数字として確定します。また、数字の間には小数点「.」が入ることもあります。
記号が押されると、計算が実行されます。しかし、計算はそのとき押された記号ではなく、その前に押された記号が使われます。
そのため、「1つ前の計算結果」「1つ前の計算記号」「直前に入力された複数の数字」「次の計算のための記号」の4つの要素が揃ったときに計算が実行されることになります。
また、記号のキーが連続して押された場合は、最後に押した計算記号が記録されます。
「=」を押すと計算が実行されますが、これに続いて数字が押されると、計算結果をクリアしなければならない。
途中で計算をクリアするボタンがないので、「=」を2度連続で押すと、クリアする機能を付けたいと思います。
<script language="javascript"> function calc_run() { }
|
【スクリプトの初期設定】 それではスクリプトを書いていきましょう。 まず、計算中の数字を入れるために変数ansを用意します。 ボタンからのイベントを受けるためにユーザー関数calc_run()も必要です。 |
(省略) <tr> (省略) |
【キーからデータを送る】 数字のキーを押すと数字を送り、記号のキーを押すと文字を送ります。 数字はそのままの数値を記入します。記号の場合は文字列なので「''」の中に書きます。
|
(省略) function calc_run(btn) { (省略) |
【キーからデータを受け取る】 キーから送られたデータは一旦変数btnで受け取ります。 まず、今押されたキーが入った変数btnの中身が数値か文字かで分岐しています。 更に、1回目の分岐のそれぞれの中にif文を使って、前に押されたキーが入っている変数keyを調べます。 記号を受け取った場合、その最後に変数btnから変数kigouに受け取ったデータを移し替えています。 そして、全体の最後には、変数btnを変数keyに入れて、後で直前のキー入力が何かを参照できるようにしています。 前のキーを調べて分岐、次に今のキーを調べて処理を分岐させるという大まかな流れを作っておきます。 |
(省略) function calc_run(btn) { (省略) |
【押したキーを画面に表示(1)】 計算は後回しにして、押されたキーを表示することにしましょう。 まずは「if (!isNaN(btn))」が真の場合です。今押したキーが数字のときの処理です。 次のif文で前のキーを判別して処理がまた2つに分かれます。 「if (!isNaN(key))」が真の場合とは、数字が押されているので、連続して数字が押されたという状況です。 次に、「if (!isNaN(key))」が偽の場合で、記号の後に数値が押されたという状況です。 2つ目の分岐が終了したところで、今入力されたキーを反映させた変数numを表示します。 |
(省略) function calc_run(btn) { (省略) |
【押したキーを画面に表示(2)】 今度は最初のif文、「if (!isNaN(btn))」が偽だった場合です。今押したキーが記号のときになります。 記号が押されたときは、変数kigouに記録が残されますので、そのまま変数kigou内の文字を画面に表示しています。 本来ならば記号が連続した場合は、記号を入れ換えるだけで終わりですが、数字の後に記号が押されたときは、計算結果も出さなくてはいけません。 |
(省略) function calc_run(btn) { (省略) |
【問題点:最初の「0」が残る】 変数numが文字列になっているので、「0」が入っているときに数字を押すと、「01」のように余計な「0」が残った数字が表示されてしまいます。 記号の後ならば、代入されるのでそれまでの変数numは消えてしまいますので、数字が連続したときの処理を、if文を使って2つに分けます。 「0」が入っているときは、入力された数字を文字列化して代入します。 「0」以外の文字列が入っているときは、その前に数字が入力されているので、後ろに文字として数字を付け足します。
|
(省略) <tr> (省略) function calc_period() {
(省略) |
【特殊なキー操作を作る:「・」】 電卓のボタンを押すと、1つだけ期待通りに動かないボタンがあります。 これは記号だけども数字の一部なので、変数numに入らなくてはいけません。 calc_period()では、変数numの後ろに「.」を付けています。 |
(省略) function calc_period() {
(省略) |
【問題点:2回目の「.」をどうするか】 これだけでは正しく動作しません。 そこで、変数numに「.」が含まれているときは、なにもしないことを決めます。 if文を足して、「indexOf()」を使います。 |
(省略) <tr> (省略) function calc_equal() { (省略) |
【特殊なキー操作を作る:「=」】 「=」の役割は、それまで貯めた数字を使って計算結果を表示するということです。これは他の記号も同じです。 まず、if文で前のキーを調べて「=」なら連続と判断して、変数ansと変数keyを初期化しています。 変数の設定が終わったら、表示部に変数ansと変数keyを表示しています。これまでは表示には変数numと変数kigouを使っていましたが、ここでは違っています。 演算には関数「eval()」が使われています。これは文字列を計算式として実行するという関数です。 |
【演算の仕組み】
「5」「+」「3」「=」と押されたときの変数の変化を追いかけましょう。まだ「+」のときは作っていませんが、eval()を同じように使います。
実際には、最初に変数を用意する段階で、およそこの流れを考えておく必要があります。
| 押されたボタン | 変数 key |
変数 num |
変数 kigou |
eval() | 変数 ans |
数字 表示 |
記号 表示 |
| "" | "0" | "" | 0 | 0 | |||
| 5 | 5 | "5" | "" | 0 | 5 | ||
| + | "+" | "0" | "+" | "05" | 5 | 5 | + |
| 3 | 3 | "3" | "+" | 5 | 3 | + | |
| = | "=" | "0" | "=" | "5+3" | 8 | 8 | = |
数字が押されたときは、変数numを数字表示に、記号が押されたときは演算結果である変数ansを数字表示に出力しています。
記号が押されると、変数numは「0」にして、次の数字が入ってくるために準備します。変数ansには計算結果が入っているので、これを表示するのです。
(省略) function calc_run(btn) { (省略) |
【計算部分を作る】 計算結果の表示は、「=」を入力した時だけでなく、四則演算の記号である「+」「−」「×」「÷」のどれかが入力されたときにも実行しなければなりません。 ここでは、前の入力が数字の場合だけ考えます。 それでは、if文の中を見て見ましょう。 計算結果が出たら、変数numは「0」にします。次に数字が入力されたら、また記録をしなくてはならないからです。 表示には変数ansを使います。次の数字が入力されるまでは、計算結果を表示しなければならないためです。
|
(省略) function calc_run(btn) { (省略) |
【問題点:続けて計算ができない】 動作テストをするといくつかの問題点が見つかります。 四則演算を続けて計算することはできるのですが、一度「=」を押すと、次の計算ができなくなるのです。 ブラウザのエラーメッセージを調べると、エラーは「ans = eval(ans + kigou + num);」のところで発生しています。
赤いマスがエラーの発生場所です。確かにブラウザの言うとおりです。 「8=7」は計算式ではありません。それを無理矢理計算させようとしたためにエラーが起きてしまったのです。 そこで、「=」の次に数字が入力されたら、変数ansと変数kigouを初期化することにします。
calc_run()の数字が入力された場合の直後に、「kigou == "="」の場合に初期化を実行します。 これだけだと、画面に表示された「=」が記号表示に残ってしまいます。 |
(省略) function calc_period() { (省略) |
【問題点:小数点の不具合(1)】 次に小数点を使った場合の2つの問題点があります。 まずは、簡単な表示の不具合を直しておきます。
「3」を押した時点で表示が「0.3」ではなく「3」になってしまいます。「=」を押してみると、答えが「8」になります。 これは、「・」が数字として扱われていないために起きています。 そこで、calc_period()の中で、「・」を数字と見なすために、「key = 0」にしてしまいます。 |
(省略) function calc_run(btn) { (省略) |
【問題点:小数点の不具合(2)】 次にはっきりとエラーが表示される問題を解決しましょう。 この不具合もまた「ans = eval(ans + kigou + num);」のところで発生しています。
これは、初めて記号を押したときにeval()が実行されることに問題があったのです。 そこで、calc_run()の記号が入力されたときにif文を使って、記号がないときは計算をしないで、「ans = num」と変数の入替だけ行います。
|
(省略) function calc_equal() { (省略) |
【問題点:小数点の不具合(3)】 演算をしている箇所はcalc_equal()の中にもあります。 |
【問題点:ブラウザの計算能力の欠陥】 実は、小数点の問題はこれで全て解決した訳ではありません。どうしても解決できない致命的な欠陥がブラウザの中にあるのです。 これはそもそものコンピュータの仕組みそのものが原因です。 最大の問題点は2進数に小数がないということなのです。小数を計算するときは、一旦整数にして計算をし、後でもう一度小数に戻すということをします。そのため、限られた桁数で計算をするために数字の小さな部分が消えてしまうのです。 計算表の専用ソフトですら、当初は2進数で計算をしていたため誤差が発生していました。10年ほど経ってようやく10進数計算ができるように改良されたくらいです。
もちろん、今後はブラウザでも10進数計算ができるようになると思われます。
|