PR

基礎をつかんだら、JavaScriptの体系的な講座で一気に実力を伸ばすのも手です。

UdemyでJavaScript講座を探す

アフィリエイト広告です。価格は変わりません。

🎯 最終演習

JavaScriptで電卓アプリを作ってみよう(総合演習)

ここまでの JavaScript レッスンで学んだことを全部つないで、動く電卓を1つ完成させます。新しい構文は出てきません。関数・switch文・try...catch・split・配列——すでに練習したものだけで作れます。

作るのは「計算エンジン」としての電卓です。"12 + 5"のような式を渡すと答えが返り、計算履歴が残ります。画面にボタンを並べる部分はDOM操作といって、このカテゴリでは扱っていないので入れていません(下の「よくある質問」で進み方を案内しています)。

1ステップずつ進むので、途中で止めてもそこまでの分は動きます。各ステップの「実行する」ボタンで、コードを書き換えて試すこともできます。

完成イメージ

最後まで進むと、こう表示されるところまで作ります。下の実行結果は、このページを作るときに実際にコードを走らせて得たものです。

12 + 5 = 17
100 - 38 = 62
7 * 6 = 42
45 / 4 = 11.25
0.1 + 0.2 = 0.3
10 / 0 → エラー: 0では割れません
3 ^ 2 → エラー: 知らない演算子です: ^

--- 計算履歴 ---
1. 12 + 5 = 17
2. 100 - 38 = 62
3. 7 * 6 = 42
4. 45 / 4 = 11.25
5. 0.1 + 0.2 = 0.3
計算できたのは 5 件です。

STEP 1四則演算を関数にする

🎯 このステップのゴール: 足す・引く・掛ける・割るを、それぞれ関数として切り出す

まずは電卓の心臓部、四則演算から作ります。a + bと直接書いてもいいのですが、あえて関数に切り出します

理由は次のステップで分かります。「+ならこの関数、-ならこの関数」と後から選べるようにするためです。処理に名前が付いていると、選んで呼び分けられます。

関数はfunction add(a, b) { return a + b; }という形です。returnを書き忘れるとundefinedが返るので気をつけてください。エラーにならず、計算結果だけが消えるので原因を見つけにくい間違いです。

実行結果
17
62
42
11.25

STEP 2演算子で処理を振り分ける

🎯 このステップのゴール: switch文で、記号に応じた関数を呼び分ける

電卓は「どの計算をするか」を記号で受け取りますcalc(12, "+", 5)と呼べるようにしましょう。

ここで活きるのがswitchです。ifを4つ並べても動きますが、「1つの値を見て行き先を選ぶ」ときはswitchのほうが意図がはっきりします

注意点が2つあります。ひとつはbreakで、書き忘れると次のcaseに流れ込みます(フォールスルー)。ただしこのコードのようにreturnで関数を抜ける場合はbreakが要りません——returnした時点で関数ごと終わるからです。

もうひとつがdefaultです。知らない記号が来たときにここへ来ます。今は文字列を返していますが、次のステップでちゃんとしたエラーにします。

実行結果
17
42
知らない演算子です
ここで使う既習レッスン

STEP 30で割る事故を防ぐ

🎯 このステップのゴール: throw でエラーを起こし、try...catch で受け止める

電卓として困るのが0で割ったときです。JavaScriptでは10 / 0がエラーにならず、Infinityという値を返します。計算が止まらないまま、おかしな値が先へ流れていきます。

そこで自分でエラーを起こしますthrow new Error("0では割れません")と書くと、その場で処理が中断して呼び出し元へ飛びます。

受け止めるのがtry...catchです。tryの中で起きたエラーはcatchに渡され、プログラム全体が止まらずに済みますerr.messageで理由の文字列を取り出せます。

「エラーを自分で起こす」のは一見おかしな感じがしますが、間違った値のまま計算を続けるほうがずっと危険です。早めに止めて理由を伝えるのが、壊れにくいプログラムの作り方です。

実行結果
12 + 5 = 17
10 / 0 → エラー: 0では割れません
3 ^ 2 → エラー: 知らない演算子です: ^

STEP 4文字で書いた式を読み取る

🎯 このステップのゴール: split で式を分解し、Number で数値に変換する

いよいよ電卓らしくします。calc(12, "+", 5)ではなく、"12 + 5"という1本の文字列を渡せるようにしましょう。

使うのはsplitです。expression.trim().split(/\s+/)と書くと、前後の空白を落としてから、空白のかたまりで区切ります。正規表現の\s+を使うのは、空白が2つ以上あってもうまく分けるためです。

ここで大事なのが型変換です。splitが返すのは文字列の配列なので、"12"のままだと"12" + "5""125"になってしまいます。Number(parts[0])数値に直してから計算します。

変換に失敗するとNaN(非数)になります。NaN === NaNfalseという有名な性質があるので、判定にはNumber.isNaN()を使います。

実行結果
12 + 5 = 17
100 - 38 = 62
あ + 5 → エラー: 数値として読めません: あ + 5
12 + → エラー: 「数値 演算子 数値」の形で書いてください: 12 +

STEP 5小数の誤差をなくす

🎯 このステップのゴール: 0.1 + 0.2 が 0.3 にならない理由を知り、丸めて直す

ここまでの電卓で"0.1 + 0.2"を計算してみてください。答えは0.30000000000000004になります。電卓としては困ります。

これは不具合ではありません。JavaScriptの数値は64ビットの浮動小数点で、0.1も0.2も2進数では正確に表せないためです。無限に続く小数をどこかで切っているので、足すとわずかな差が残ります。同じことはPythonでもJavaでも起こります。

対策は丸めることです。Math.round(value * 1e10) / 1e10と書くと、いったん10桁ぶん大きくして整数に丸め、また戻します。誤差は小数第16位あたりに出るので、第10位で丸めれば消えます。実際に使う桁数は問題ありません。

お金の計算では、この方法でも足りません。1円単位で正確に扱いたいときは、はじめから「円」ではなく「銭」のような整数で持つのが定石です。誤差の出ない世界に持ち込んでしまう、という考え方です。

実行結果
丸める前: 0.30000000000000004
丸めた後: 0.3
等しいか: false
丸めれば: true

STEP 6計算履歴を残して仕上げる

🎯 このステップのゴール: 配列に履歴を積み、まとめて表示して完成させる

最後の仕上げです。計算するたびに履歴を配列へ積んで、最後にまとめて表示します。これで電卓の完成です。

履歴はconst history = []で用意し、history.push(...)で足していきます。constなのに中身を足せるのを不思議に思うかもしれません。constが禁じているのは「その変数に別のものを入れ直すこと」で、配列の中身を変えるのは止めません。

表示にはforEachを使い、${i + 1}で1から始まる番号を付けています。配列の添字は0から始まるので、人が読む番号にするには1を足します。

エラーになった式は履歴に入りませんhistory.pushevaluateの中、しかもthrowより後にあるからです。途中でthrowすると、それより下は実行されません——この性質をそのまま使っています。

完成です。run("...")の式を書き換えて、いろいろ計算させてみてください。

実行結果
12 + 5 = 17
100 - 38 = 62
7 * 6 = 42
45 / 4 = 11.25
0.1 + 0.2 = 0.3
10 / 0 → エラー: 0では割れません
3 ^ 2 → エラー: 知らない演算子です: ^

--- 計算履歴 ---
1. 12 + 5 = 17
2. 100 - 38 = 62
3. 7 * 6 = 42
4. 45 / 4 = 11.25
5. 0.1 + 0.2 = 0.3
計算できたのは 5 件です。

よくある質問

画面にボタンを並べた電卓にするには?

ボタンを押して動く電卓にするにはDOM操作(document.querySelectoraddEventListener)が必要ですが、これはJavaScriptカテゴリでは扱っていません。無理に入れると未習の内容だらけになるので、このページでは計算エンジンまでを作っています。

見た目を作るところはHTML/CSSカテゴリが近道です。このページで作ったevaluate()はそのまま使えます。ボタンからevaluate()を呼ぶだけで画面付きの電卓になります。

エラーが出て動きません

多いのはreturnの書き忘れです。関数がundefinedを返しますがエラーにはならないので、計算結果だけが消えます。

次に多いのがバッククォートの打ち間違いです。${...}を使うテンプレートリテラルは、囲む記号がシングルクォートではなくバッククォートです。ここを間違えると${a}がそのまま文字として出ます。

かっこ付きの式も計算したい

"(1 + 2) * 3"のような式を扱うには、優先順位を解釈する仕組みが要ります。その第一歩が括弧の対応をチェックしようで学ぶスタックです。まずはこのページの形を動かしてから進むのがおすすめです。

🚩 次はこのカテゴリへ

電卓の中身ができたら、次は見た目です。HTML/CSSカテゴリでは、ここで作った計算エンジンに画面を付けるための土台——ボタンやレイアウトの作り方を学べます。

HTML/CSSのレッスンへ進む
広告スペース(バナー)
広告スペース(記事内)