前言
今天面试的时候也是遇到一家公司的面试官,我以为它会像往常的面试官一个,先让我做个自我介绍,结果没想到上来就给我一道面试题,让我先手写一个计算器,我感觉还蛮有意思的,就自己尝试了一下,也是实现了一些基本的计算器功能,这里我就来给大家分享一下
正文
实现思路
要实现一个这样的简易计算器,首先咱们就要在输入框部分,显示咱们刚刚输入的数字或者符号,这里我是直接通过原生js获取输入框的dom结构,使用getElementById方法获取id为display的输入框元素,并通过.value将它显示在输入框上的,如果用vue写的话,也可以直接在input框里用v-model双向绑定我们输入的数据,然后就是设置四个函数appendNumber(number)、appendOperator(operator)、 clearDisplay()、calculateResult()来实现当用户分别点击数字、操作符、清空按钮、‘=’计算按钮时触发的事件,实现这四个功能就差不多了。
具体实现
首先关于页面布局,我就用了一个输入框和许多button按来呈现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>简易计算器</title>
</head>
<body>
<div class="calculator">
<input type="text" id="display" />
<div class="buttons">
<!-- 按钮 -->
</div>
</div>
</body>
</html>
然后关于按钮的样式,就是其实计算器里的按钮排放的都很整齐,一行一列的排放,所以首先想到的就是弹性布局,这里我用的是网格布局,原理和弹性布局差不多,
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
}
.buttons {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 5px;
}
这里将body设置为弹性容器是为了让这个计算器在浏览器的正中间呈现,然后再将buttons父容器设置成网格布局,通过grid-template-columns: repeat(4, 1fr)定义一个网格布局中的列布局。将容器划分为四列,并且每一列的宽度为可用空间的等分之一。这样里面的每一个按钮就可以有序排放了。
最后就是js中这四个函数的实现了
appendNumber(number)
function appendNumber(number) {
const display = document.getElementById('display');
//console.log(display);
display.value += number;
//console.log(display.value);
}
appendNumber(number): 向显示屏追加数字。当用户点击数字按钮时,该按钮的onclick事件触发appendNumber(7)函数。该函数接收一个参数number,表示用户点击的数字。函数内部获取到<input>元素,并将其当前值与数字7相加。最后更新<input>元素的值。
- 获取输入框:
const display = document.getElementById('display');: 使用getElementById方法获取id为display的输入框元素。
- 追加数字:
display.value += number;: 将用户点击的数字追加到输入框当前的值后面。这里的+=操作符将新的数字附加到display.value的末尾。
appendOperator(operator)
function appendOperator(operator) {
const display = document.getElementById('display');
// 防止连续输入运算符
if (display.value.endsWith('+') || display.value.endsWith('-') ||
display.value.endsWith('*') || display.value.endsWith('/')) {
return;
}
// 不允许在没有任何数字的情况下输入负号
if(operator === '-' && display.value === '') {
return;
}
display.value += operator;
}
这个函数用于向计算器显示屏追加运算符。
-
获取显示屏元素:
const display = document.getElementById('display');: 使用getElementById方法获取id为display的<input>元素。 -
防止连续输入运算符:
if (display.value.endsWith('+') || display.value.endsWith('-') || display.value.endsWith('*') || display.value.endsWith('/')) { return; }这段代码检查显示屏当前的值是否以任何一个运算符(
+,-,*,/)结尾。如果是,则阻止进一步的操作,即不追加新的运算符。
-
不允许在没有任何数字的情况下输入负号:
if (operator === '-' && display.value === '') { return; }这段代码检查如果用户输入的是负号
-,并且显示屏当前为空(即display.value的值为'')。如果满足这两个条件,则阻止负号的追加。
-
追加运算符:
display.value += operator;: 如果上述条件都不满足,则将用户点击的运算符追加到显示屏的当前值后面。
clearDisplay()
function clearDisplay() {
const display = document.getElementById('display');
display.value = '';
}
这个函数用于清空计算器显示屏上的内容
-
获取显示屏元素:
const display = document.getElementById('display');: 使用getElementById方法获取id为display的<input>元素。 -
清空显示屏内容:
display.value = '';: 将<input>元素的值设置为空字符串'',从而清空显示屏上的内容。
calculateResult()
function calculateResult() {
const display = document.getElementById('display');
try {
// 使用Function构造函数避免eval的安全问题
const result = new Function(`return ${display.value}`)();
display.value = result;
} catch(error) {
alert("无效的表达式");
display.value = '';
}
}
这个函数用于计算计算器显示屏上的数学表达式的结果,并将结果显示在显示屏上。
-
获取显示屏元素:
const display = document.getElementById('display');: 使用getElementById方法获取id为display的<input>元素。 -
计算结果:
try { ... }: 使用try块来捕获可能发生的错误。const result = new Function(return ${display.value})();
这里咱们用Function构造函数来安全地计算显示屏上的数学表达式。
new Function(return display.value‘)‘:创建一个新的匿名函数,该函数的主体是return{display.value}其中${display.value}会被替换成显示屏上的实际值。(): 立即执行这个新创建的函数,得到计算结果,并将其存储在result变量中。display.value = result;: 将计算结果赋值给<input>元素的值,从而更新显示屏。 -
处理错误:
catch (error) { ... }: 如果在计算过程中发生错误(例如无效的表达式),则捕获这个错误。alert("无效的表达式");: 显示一个警告对话框,告知用户输入的表达式无效。display.value = '';: 清空显示屏的内容。
其实在上面计算函数结果这个地方我使用Function构造函数来安全地计算一个字符串形式的数学表达式的方法之一,new Function 是一个特殊的构造函数,它接受一个或多个字符串参数,并返回一个新的函数对象。字符串参数构成了新函数的源代码。当然也可以用内置函数eval来计算最后的结果,它的功能也很强大,但是它有个缺点就是不太安全,所以我使用Function构造函数来执行字符串形式的代码比使用eval更安全,因为Function构造函数在执行时会创建一个新的作用域,不会污染全局作用域。
好啦,今天的分享就到这里啦。最后给大家附上完整的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>简易计算器</title>
</head>
<body>
<div class="calculator">
<input type="text" id="display" />
<div class="buttons">
<button onclick="clearDisplay()">C</button>
<button onclick="appendNumber('7')">7</button>
<button onclick="appendNumber('8')">8</button>
<button onclick="appendNumber('9')">9</button>
<button onclick="appendOperator('+')">+</button>
<button onclick="appendNumber('4')">4</button>
<button onclick="appendNumber('5')">5</button>
<button onclick="appendNumber('6')">6</button>
<button onclick="appendOperator('-')">-</button>
<button onclick="appendNumber('1')">1</button>
<button onclick="appendNumber('2')">2</button>
<button onclick="appendNumber('3')">3</button>
<button onclick="appendOperator('*')">*</button>
<button onclick="appendNumber('0')">0</button>
<button onclick="appendOperator('.')">.</button>
<button onclick="calculateResult()">=</button>
<button onclick="appendOperator('/')">/</button>
</div>
</div>
</body>
</html>
<script>
function appendNumber(number) {
const display = document.getElementById('display');
//console.log(display);
display.value += number;
//console.log(display.value);
}
function appendOperator(operator) {
const display = document.getElementById('display');
// 防止连续输入运算符
if (display.value.endsWith('+') || display.value.endsWith('-') ||
display.value.endsWith('*') || display.value.endsWith('/')) {
return;
}
// 不允许在没有任何数字的情况下输入负号
if(operator === '-' && display.value === '') {
return;
}
display.value += operator;
}
function clearDisplay() {
const display = document.getElementById('display');
display.value = '';
}
function calculateResult() {
const display = document.getElementById('display');
try {
// 使用Function构造函数避免eval的安全问题
const result = new Function(`return ${display.value}`)();
display.value = result;
} catch(error) {
alert("无效的表达式");
display.value = '';
}
}
</script>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
}
.calculator {
border: 1px solid #ccc;
padding: 20px;
background-color: white;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
input {
width: 100%;
height: 40px;
margin-bottom: 10px;
text-align: right;
font-size: 18px;
}
.buttons {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 5px;
}
button {
height: 40px;
font-size: 18px;
cursor: pointer;
}
</style>