1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptで電卓を作る3

1
Last updated at Posted at 2025-12-14

JavaScriptで電卓を作る3

CleanShot 2025-12-10 at 06.34.53@2x.png

こんにちは、tushiko23です 👋
今回はついに 計算処理の仕上げ をやっていきます!

例として、次の計算で考えます👇

3 - 1 + 2 × -4 ÷ 2 = -2

前回は、display に連結された文字列を分解し、
 - を 符号(単項マイナス) と 演算子(引き算) に判定して、次の配列にできるところまで進みました。

tokens = ['3','-','1','+','2','*','-4','/','2']

今日はここから、

  • 掛け算・割り算(* /)を優先して計算する

  • = 押下時に 足し算・引き算(+ -)を処理して結果表示する

この2つを加えて、電卓を完成させます!🎉
それでは順番に見ていきましょう!

① 掛け算・割り算の優先順位を処理する ✖️➗

四則演算は * / が + - より優先 されます。
なので、先に * / を処理し、配列を「足し算・引き算だけ」に整えます。

今回の例だとイメージはこんな感じ👇


// まずこれがある
['3','-','1','+','2','*','-4','/','2']

// 2 * -4 を先に計算して
['3','-','1','+','-8','/','2']

// -8 / 2 も計算して
['3','-','1','+','-4']

applyMulDiv のコード(* / を優先計算する)
function applyMulDiv(tokens) {
  const result = [];
  let i = 0;

  while (i < tokens.length) {
    const t = tokens[i];

    if (t === "*" || t === "/") {
      const prev = Number(result.pop());
      const next = Number(tokens[i + 1]);

      let calc;
      if (t === "*") {
        calc = prev * next;
      } else {
        if (next === 0) {
          display.value = "0では除算できません";
          return null;
        }
        calc = prev / next;
      }

      result.push(String(calc));
      i += 2; // 演算子と次の数をまとめて消費する
    } else {
      result.push(t); // 数字や + - はそのまま残す
      i++;
    }
  }

  return result;
}

処理の要約(めちゃ大事)📌

* or / が出てきたら
✅ 前の数(result.pop) と ✅ 次の数(tokens[i+1]) を取り出して計算
✅ 計算結果を result に入れる
✅ i += 2 して 次の数までまとめて消費

それ以外(数字や + -)は
✅ そのまま result に入れる
✅ i++

例:['3','-','1','+','2','*','-4','/','2'] を処理してみる

最初に * が出てくるのはここ👇

2 * -4

この時点での配列はこうなっています:

result = ['3','-','1','+','2']
tokens = ['3','-','1','+','2','*','-4','/','2']
i = 5  // tokens[5] が "*"

✅ 前後の数を取り出す

prev = Number(result.pop());   // 2
next = Number(tokens[i + 1]);  // -4

✅ 計算して result に戻す

calc = prev * next;  // 2 * -4 = -8
result.push(String(calc));

ここまでで result は👇

result = ['3','-','1','+','-8']

そして i += 2 なので、

*と -4 はまとめて消費され、次は / の位置へ進みます。

次の / を処理する

今度は、-8 / 2となるので、

prev = -8
next = 2
calc = -4

結果、applyMulDiv の返り値はこう👇

['3','-','1','+','-4']

🎉 これで「足し算・引き算だけの配列」になりました!

② = 押下時に + - を計算して表示する 🟰

次は equal() の中で、

表示(× ÷)を内部用(* /)に変換して、tokens を作ります。

  1. mergeUnaryMinus で -4 を1要素にする

  2. applyMulDiv で * / を先に計算

  3. 残った + - を左から順に計算

  4. 表示する

という流れになります!

equal の中身(+ - の計算部分)
let result = Number(tokens[0]);

for (let i = 1; i < tokens.length; i += 2) {
  const op = tokens[i];
  const num = Number(tokens[i + 1]);

  if (op === "+") {
    result = result + num;
  } else if (op === "-") {
    result = result - num;
  }
}

ここでのポイントは👇

tokens は ['数', '演算子', '数', '演算子', '数', ...] の形

なので i += 2 で 演算子の位置だけ見ればOKです。

例:['3','-','1','+','-4'] を計算する

最初に

result = 3

そこから順番に処理します👇

3 - 1 = 2

2 + (-4) = -2

結果は -2 になります 🎉

小数点の誤差対策(丸め処理)🔧

割り算や小数は、JavaScriptの仕様上誤差が出ることがあります。
そこで最後に、小数点を丸めて誤差を抑えます。

result = Math.round(result * 1000000000) / 1000000000;

小数点第9〜10位あたりで丸めることで、
例えば 0.1 + 0.2 問題みたいな誤差を軽減できます。

エラー制御 🚧

電卓は「どんな入力でも壊れない」ことが大切なので、以下も入れています。

  • 何も入力せず = → 何もしない

  • 「0では除算できません」表示中に = → 0に戻す

  • 末尾が演算子(例:3+ / 3-)で = → 何もしない(値保持)

  • 関数の返り値が null のとき → 後続を止める

このあたりを入れておくと、実際の電卓っぽさが一気に上がります 👍

✅ まとめ

今回やったことはこの2つです!

(1) * / を先に計算して tokens を整理する

(2) 残った + - を左から順に計算して結果を出す

これで = を押したときに計算結果が出る、
本格的な電卓アプリが完成しました 🎉

あとがき ✍️

電卓って「ボタン押したら計算するだけでしょ?」と思いきや、
実際に作ってみると 入力制御・例外処理・優先順位 が山ほどあって、めちゃくちゃ勉強になりました。

特に、

-(マイナス) を符号として扱う

演算子が連続したときの挙動

*(かける) /(わる) を優先して計算するための配列処理

この辺りを自分で書けるようになると、
文字列処理・配列処理・条件分岐の理解が一気に深まる感覚がありました。

ここまで読んでいただきありがとうございました!🙌
「ここもっと詳しく!」や「こういう入力も対応したい!」などあれば、コメントでもDM頂ければ励みになりますので、ぜひよろしくお願いします:pray:

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?