I'm working on a Calculator app. I'm collecting the numbers (1,2,3…) and operators (+,-,*,/, =) as parameters from html onclick method and using eval() in JavaScript to compute the expression. Something like this..
<button type="submit" class="button-style" onclick="myfunc('7')" id="seven"> 7 </button>
<button type="submit" class="button-style" onclick="myfunc('8')" id="eight"> 8 </button>
<button type="submit" class="button-style" onclick="myfunc('9')" id="nine"> 9 </button>
My JavaScript file:-
function myfunc(para) {
if (para != "=" && para != "AC" && para != "ERS" && para != "+/-") {
document.getElementById("user-input").innerHTML += para;
document.getElementById("user-input").style.display = "block";
} else if (para === "ERS") {
document.getElementById("user-input").innerHTML = document
.getElementById("user-input")
.innerHTML.slice(0, -1);
} else if (para === "AC") {
document.getElementById("user-input").innerHTML = " ";
document.getElementById("result").innerHTML = " ";
} else if (para === "+/-") {
let newvar = document.getElementById("user-input").innerHTML;
let anothervar = newvar * -1;
document.getElementById("user-input").innerHTML = anothervar;
} else {
let evaldata = document.getElementById("user-input").innerHTML;
let newevaldata = evaldata.replace(/^0+/, ""); //Omitting the leading zeroes
let resultData = eval(newevaldata);
let num = resultData.toFixed(2);
document.getElementById("result").innerHTML = num;
}
}
And this is how the calculator looks like:- Calculator
Everything is working fine except one strange issue.
Whenever I try to add 010+100
it shows the result as 108
or if I try 0000010+1000
the result is 1008
, or 0023+3200
gives 3219
.
How is that possible and how to omit the preceding zeroes, I have tried with a regular expression but it doesn't work. Without having preceding zeros the app works just fine. I am stuck here. Please help me out. Thanks.
Here is a screenshot:- calculation error
Never use eval
. It's considered evil specially from a user-input — since it evaluates inside the browser any user-submitted value.
Use new Function
instead.
Although (as mistakenly suggested) being an issue of parseInt()
— it's not.
parseInt("010")
will return the correctly expected 10
10 (base 10) in all modern browsers. There's a deprecation of 0
-prefixed octal literals in strict-mode which can be seen at work by specifically using parseInt
, as seen.
The issue is strictly with the 010
Octal representation due to the leading 0
— in "sloppy mode"
console.log(010) // 8
You could adhere to a more battle-proof syntax by using Strict Mode
"use strict" console.log(010) // Uncaught SyntaxError: Octal literals are not allowed in strict mode
eval("010 + 100")
evaluates the first operand 010
as octal (value 8
in decimal), resulting in 8 + 100
. Just like doing ie: parseInt("011", 8) === 9; // true
parseInt("011", 8) === 9; // true
by using intentionally the radix 8
.
Even if suggested to use new Function
- the issue still remains true
"use strict"; console.log(new Function("return (010 + 100);")()) // 108
therefore: it's your job as a developer to:
get rid of any leading "0"
from your String before passing them to new Function
.
Finally, back to your specific code:
new Function
instead of evil
(OK, you got that one by now)<button type="submit"
should be <button type="button"
on*
handlers like onclick="myfunc('1')"
. JS should be in one place only, and that's the respective <script>
tag or file. Use Element.addEventListener() instead.document.getElementById("user-input").innerHTML
from a contenteditable
element. Contenteditable is a total browser mess and we're still waiting for a better API to emerge - and it's an unreliable. Use document.getElementById("user-input").value
instead, from an <input>
Element.Given all the hints above, here's how you could proceed:
// DOM utility functions: const el = (sel, par) => (par || document).querySelector(sel); const els = (sel, par) => (par || document).querySelectorAll(sel); // Calculator: const calculator = (elCalculator) => { const elInput = el("input", elCalculator); const elsButtons = els("button", elCalculator); let isReset = false; function buttonHandler() { const sym = this.textContent, // Button Symbol val = elInput.value; // Value currently on screen let isEQ = sym === "=", isAC = sym === "AC", isDl = sym === "⌫", result = ""; if (isReset) { isReset = false; result = sym; } else if (isDl) { result = val.slice(0, -1) || "0"; } else if (isAC) { result = 0; } else if (isEQ) { try { result = new Function(`return (${val});`)(); } catch { isEQ = false; result = val; } } else { result = (val + sym).replace(/^0(?=[^\.]+$)/, ""); } elInput.value = result; isReset = isEQ; } elsButtons.forEach(elBtn => elBtn.addEventListener("click", buttonHandler)); }; // Init: els(".calculator").forEach(calculator);
/* QuickReset */ * { margin: 0; box-sizing: border-box; } /* Calculator */.calculator { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem; max-width: 400px; }.calculator > * { padding: 0.5rem 1rem; }.calculator > input { text-align: right; }.calculator > input, .calculator > button:last-child { grid-column-start: 1; grid-column-end: 5; }
<div class="calculator"> <input type="text" value="0" readonly> <button type="button">(</button> <button type="button">)</button> <button type="button">AC</button> <button type="button">⌫</button> <button type="button">7</button> <button type="button">8</button> <button type="button">9</button> <button type="button">*</button> <button type="button">4</button> <button type="button">5</button> <button type="button">6</button> <button type="button">/</button> <button type="button">1</button> <button type="button">2</button> <button type="button">3</button> <button type="button">+</button> <button type="button">E</button> <button type="button">0</button> <button type="button">.</button> <button type="button">-</button> <button type="button">=</button> </div>
in where, amongst its simplicity, the most interesting parts are:
result = new Function(
return (${val}); )();
instead of eval()
result = (val + sym).replace(/^0(?=[^\.]+$)/, "");
to clear the needed "0"
only if needed.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.