0%

JS地下城 - 3F - 計算機

作品

JS地下城 - 3F - 計算機

主體架構

利用建構式函式做為主架構,在此建構函式內增加要用的函式來處理不同功能。其函式內包含 :

  • this ,可以賦予給變數確保指向自己
    • 例如 let vm = this
  • 運算用的暫存資料,初始值為空陣列
    • 後續加入資料時,例如 ['1', '+', '1']
  • 實際要顯示的暫存資料,初始值為空陣列
    • 後續加入資料時,例如 ['1', '÷', '1']
    • eval( ) 無法處理特殊符號 ÷
  • 計算函式,用來產生最終結果
  • 運算符號函式,條件判斷後,將數字與符號加入暫存陣列
  • 顯示用函式,將輸入的數字產生累加數字字串
  • 其他格式化函式,例如千分位與小數點判斷
  • 按鈕與按鍵函式,提供給事件監聽用

目標功能

  • 連續輸入數字
    • 按下或點擊數字鍵時,數字字串累加
    • Array.from() : 將對象轉為陣列
    • join() : 將陣列內資料作為字串串接
    • .toString() : 將對象轉成字串
  • 移除最後一個數字
    • 一樣將對象轉為陣列,利用 .pop() 將最後一個資料移除後,再利用 join() 組合
  • 紀錄輸入數字與運算符號
    • 按下或點擊運算符號時,紀錄所輸入數字與運算符號
  • 計算輸入數字
    • 按下等於時,計算結果
    • eval() : 將一連串的字串作為數學式計算

功能範例

節錄與簡化所做功能,主要先了解方法的使用,當監聽事件輸入數字時,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// 取得 DOM,其為 html 的 <input>,具有 value
const input = document.querySelector('.js-displayNum')
// 要計算的暫存顯示資料
const sumTemp = document.querySelector('.js-sumTemp')
// 建構函式
const cal = function () {
let vm = this // 確保指向此物件
let storageAry = [] // 暫存資料
let displayAry = [] // 暫存資料實際顯示

// 計算輸入數字
this.sum = () => {
storageAry.push( vm.numberStr() )
input.value = ''
vm.display(eval(storageAry.join('')))
vm.displayFontSize()
}

// 紀錄輸入數字與運算符號
this.arithmetic = (operator) => {
// 計算用資料
switch (operator) {
case '+' : storageAry.push( vm.numberStr() , '+' )
break
case '−' : storageAry.push( vm.numberStr() , '-' )
break
case '×' : storageAry.push( vm.numberStr() , '*' )
break
case '÷' : storageAry.push( vm.numberStr() , '/' )
break
}
// 顯示用資料
displayAry.push( vm.numberStr() , operator )
sumTemp.value = displayAry.join('')
// 清空顯示欄
input.value = ''
}

// 連續輸入數字,累加字串
this.dispay = (num) => {
input.value += num.toString()
}

// 移除最後一個數字
this.backspace = () => {
let str = Array.from( input.value )
str.pop()
input.value = str.join('')
}

// 格式化輸入數字為字串與小數點判斷
this.numberStr = () => {

}
// 判斷字體大小
this.displayFontSize = () => {

}

// 監聽事件
this.keydown = (e) => {}
switch(e.code){
case "backspace":
vm.backspace
break
case 'Numpad1':
vm.display(1)
break
}
}

// 將函式轉為物件,也就是建構式函式
const jsCal = new cal()

// 監聽事件,當輸入對應的鍵盤按鍵時,會執行該功能
window.addEventListener( 'keydown', jsCal.keydown )

畫面顯示

數字千分位

  • 正規表達式
    • 數字字串.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",")
  • 取得本地字串格式
    • 數字.toLocaleString('en-US')
    • 會被截取為整數

數字長度縮放

  • JavaScript,判斷字串長度,當超過一定長度時增加與移除 class
  • CSS,字體大小調整,並固定欄位高度,否則高度會隨著字體大小做變化

按鍵功能

計算機上分別有數字鍵、運算符號鍵以及 Enter / 等於鍵,按下或點擊它們會執行不同的功能。

數字鍵 🔢

按下數字鍵時,目前已寫的功能有 :

  • 按下數字鍵後,字串相加,渲染畫面
  • 小數點格式判斷, ‘.1’ 則變成為 ‘0.1’
  • 顯示欄為 0 ,不得執行 ‘00’,若鍵入新數字則為新數字
    • 00001
    • 0.1、0.00001、100
    • 第一個字串為 0
      • 前面沒有數字,不得連續輸入 0
      • 若顯示欄為 0 ,按下其他數字改為其他數字開頭
      • 若顯示欄為 0 ,按下小數點正常串接

運算符號 +-*/

按下 +-*/ 時,

  • 改變目前顯示的運算符號
  • 根據按下的運算符號將現值與運算符號加入暫存陣列

Enter / 等號 =

按下 Enter / 等號時,
將暫存陣列內的所有資料,轉成字串後,利用 eval() 做運算並清空暫存陣列,接著再判斷下一個行為 :

  • 若按下 +-*/
    • 將現值結果儲存進暫存陣列
  • = 後再次按 =
    • 維持現狀 return
    • 若顯示欄為空則給 0
  • 按下新數字鍵 🔢
    • 鍵入新數字,清空顯示欄後顯示新數字

問題處理

小數點問題

0.1 + 0.2 = 0.30000000000000004

  • 以 64 位浮點數形式儲存
  • 0.3 之二進位轉成十進位永遠不會等於 0.3

解決方式

  • parseFloat(數字.toPrecision(12))
    • parseFloat('0.123455')
      • 將字串或數字浮點數轉成數字浮點數
    • .toPrecision(數字)
      • 顯示小數點後指定位數
      • 若有大於 0 的位數,則優先顯示
      • 最後一位數會根據下一位數四捨五入
      • 123.456.toPrecision(4) -> 123.5
      • 0.123456.toPrecision(4) -> 0.1235
  • parseInt('123456')
    • 將字串或數字轉成整數
    • parseInt('0.1') -> 0
    • parseInt('0.11234564') -> 0
  • .toFixed(指定位數)
    • 結果為字串且為四捨五入

參考來源

  1. camsong - JavaScript 浮点数陷阱及解法
  2. Summer。桑莫。夏天 - 你懂 JavaScript 嗎?#5 值(Values)Part 1 - 陣列、字串、數字
  3. AlenWu - [Javascrpt]轉換數字成含千分位的文字
  4. MDN - Number.prototype.toLocaleString()
  5. SlashView - Javascript之數值千分位符號(Comma)的顯示