[有手就行系列]简单易懂的两百行js计算器

序言

本篇仅给没有思路的同学们提供参考,请勿用于交作业,或者商业(应该是不可能的)用途,老大哥在看着你.
惯例:阿巴阿巴阿巴阿巴阿巴

项目的准备

首先,你需要一个编译器,那种都可以,初学者我推荐Hbuilder.
然后在编译器中(或许是你的文件夹中)新建一个项目.并且在项目中新建两个文件夹,js与css.通常惯例中,我们把js代码与css分开存放,而不是与index.html放在同一级中.在小型项目中这或许难以理解.有些画蛇添足的味道.
很多习惯都是如此,在当时觉得麻烦不省事,但当你需要构建的是一个大型项目时,这些良好的习惯会帮助你省很多事,
在前端中,html5负责建构静态网页,CSS3负责装饰布局页面,js负责动态页面以及与后端的交互,所以我们完成这个项目的过程也是如此.先写好页面(html以及css),再思考逻辑(js).
最后,再次提醒,如果你进来只是为了COPY代码完成作业的,那你在就业时就会流下悔恨的眼泪.这是你个人的选择.而愿意学习自我提高的同学,请跟上我的思路.并且在同时思考问题:有没有更好的实现方法?我能不能做得更好更美观?

[1]不光简单还有些难看的前端

下面是h5与C3代码,布局方式使用的是浮动

CSS3{
	float: left;
}

页面相当朴素,代码量很少,所以直接使用了内联css

计算器
	<link rel="stylesheet" type="text/css" href="./css/work.css"/>

	<script src="./js/jquery-3.1.1.min.js" type="text/javascript" charset="utf-8"></script>
	<script src="./js/work.js" type="text/javascript" charset="utf-8"></script>
	
	<style type="text/css">
		*{/* 取消边框 */
			margin: 0px;
			padding: 0px;
		}
		body{/* 设置body的外边距 */
			padding-left: 30%;
			padding-right: 30%;
		}
		
		.CountButton{
			margin-left:2% ;
			margin-bottom: 20px;
			float: left;
			width: 22%;
			height:50px;
			border:2px black solid;
		}
		#Count{
			width: 300px;
			height: 500px;
			padding: 20px;				
			border:2px black solid;
		}
		#CountShow{
			float: left;
			width: 100%;
			height:70px;
			margin-bottom: 20px;
			padding-top: 10px;
			border:2px black solid;
		}
		#Rlist{
			float: left;
			width: 100%;
			height:30px;
			margin-bottom: 20px;
			border:2px black solid;
		}
		#ButtonList{
			float: left;
			width: 100%;
			padding-top: 2%;
			padding-bottom: 2%; 
			height:330px;
			border:2px black solid;
		}
		.InputShow{
			float: right;
			height:30px;
			width: 100%;
			text-align: right;
		}
	</style>
</head>
<body>
	<div id="Count">
		<div id="CountShow">
			<font id="Countformula" class="InputShow" size="4" color="" style="margin-bottom: 10px;"></font>
			<font id="Addformula" class="InputShow" size="4" color="" ></font>
		</div>
		<div id="Rlist">
			<font id="Result" class="InputShow" size="4" color="" ></font>
		</div>
		<div id="ButtonList">
			<button id="" class="CountButton Count" data-count="+">
				<font size="3" color="">加(+)</font>
			</button>	
			<button id="" class="CountButton Count" data-count="-">
				<font size="3" color="">减(-)</font>					
			</button>			
			<button id="" class="CountButton Count" data-count="*">
				<font size="3" color="">乘(*)</font>				
			</button>	
			<button id="" class="CountButton Count" data-count="/">
				<font size="3" color="">除(/)</font>					
			</button>		
				
				
			<button id="" class="CountButton Dispose" data-dispose="C">
				<font size="3" color="">清除(C)</font>					
			</button>	
			<button id="" class="CountButton Dispose" data-dispose="B">
				<font size="3" color="">退格(B)</font>
			</button>			
			<button id="" class="CountButton Count" data-count="(">
				<font size="3" color="">括号"("</font>
			</button>	
			<button id="" class="CountButton Count" data-count=")">
				<font size="3" color="">括号")"</font>		
			</button>	
				
		
				
			<button id="" class="CountButton Cnumber" data-event="1">
				<font size="4" color="">(一)</font>
			</button>	
			<button id="" class="CountButton Cnumber" data-event="2">
				<font size="4" color="">(二)</font>
			</button>			
			<button id="" class="CountButton Cnumber" data-event="3">
				<font size="4" color="">(三)</font>
			</button>	
			<button id="" class="CountButton Cnumber" data-event=".">
				<font size="3" color="">小数点(.)</font>		
			</button>
					
					
			<button id="" class="CountButton Cnumber" data-event="4">
				<font size="4" color="">(四)</font>
			</button>	
			<button id="" class="CountButton Cnumber" data-event="5">
				<font size="4" color="">(五)</font>
			</button>			
			<button id="" class="CountButton Cnumber" data-event="6">
				<font size="4" color="">(六)</font>
			</button>	
			<button id="" class="CountButton Cnumber" data-event="0">
				<font size="4" color="">(零)</font>	
			</button>
			
			
			<button id="" class="CountButton Cnumber" data-event="7">
				<font size="4" color="">(七)</font>
			</button>	
			<button id="" class="CountButton Cnumber" data-event="8">
				<font size="4" color="">(八)</font>
			</button>			
			<button id="" class="CountButton Cnumber" data-event="9">
				<font size="4" color="">(九)</font>
			</button>	
			<button id="" class="CountButton Dispose"  data-dispose="=">
				<font size="3" color="">等于(=)</font>
			</button>
		</div>
	</div>
</body>
页面效果 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200707171326669.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2h1aXNlc2h1YWlrYWk=,size_16,color_FFFFFF,t_70#pic_center)

[2]不难理解还有些弱智的js代码

在贴代码之前,请诸位先思考,你平时是如何计算如10+(10*10+10)/10这类算式的?是不是先在括号里找乘除法,然后计算括号内的加减法.以此推类.如果不清楚的建议回小学回炉重造,学习算数优先级.
在这里插入图片描述
开个玩笑.
基本的逻辑确实如此,以上面的10+(10*10+10)/10为例
步骤
1: 10+(10*10+10)/10
2: 10+(100+10)/10
3: 10+110/10
4. 10+11
5. 21
我们明白了计算的逻辑,非常的简单,但是使用js代码实现这个逻辑,并输出结果.其中的业务逻辑就有些令人费解了.
在解决简单地二元乘除问题时,我们可以依次获取操作对象,如a,+,b,再使用switch区分处理乘除问题.但在这个问题中我们要考虑计算优先级的问题,不能简单地循环处理.
请思考一下,如果是你的话,你要如何实现?使用何种方法?
用伪代码的方式思考就可以了,并不用具体的步骤,给大家三十秒…

我是十秒钟的分割线


我是十秒钟的分割线


我是十秒钟的分割线


想到的同学可以在评论中写出来,有需要我可以帮助完成代码的实现,现在言归正传.如何实现根据算式的乘除号以及括号,来决定算式的计算顺序?
有些同学会想,诶呀,使用split()将算式以一定方式分开,再依次进行计算不就好了?
确实,这也是一种解决方式,当但算式为((10+10)*10)+(10/10+10)这类优先级关系复杂的算式时,这类取巧简单地方式就不适用了.我们需要的是一个能够自动根据计算优先级进行计算的解决方式.
比如,递归调用.
有些同学这时候就要举手提问了.
阿巴阿巴,我知道递归调用可用来解决阶乘问题,但是递归和解决算数优先级之间有什么关系吗?递归流程
当然有关系,并且契合度还挺高的.我们先以算式((((10+10)*10)+(10/10+10)))做个假设:
首先使用递归调用的递推阶段,将算式中的一个个计算单元分解,直至不可再分
1:((10+10)*10)+(10/10+10)
2:((10+10)10)
3:(10+10)
4:10不可再分了
回归
1:处理(10+10)=20,将20传递至上一个函数
2:处理(20
10)=200,将200传递至上一个函数
3:200+(10/10+10)),再处理(10/10+10)这个计算单元
以此推类
在这里插入图片描述有些机智的小伙伴可能已经发现了,在这个递归递推分解算式的过程中,分割的方式是括号优先,而同一个括号中的加减号分割计算的单元
根据这些伪代码思想,可以写出以下js代码
完整代码.需要放在word.js中

var Formula = "(15*10+15)*10";//测试用的算式,实际使用时要置空
var CountRequest = "=";

var CountFormula = [];

window.onload = function (){
	//测试用
	$("#Countformula").html(Formula);
	$("#Result").html(CountRequest);
	
	// 数字处理
	$(".Cnumber").click(function(){
		var CNumber = $(this).attr("data-event");
		Formula = Formula+CNumber;
		$("#Countformula").html(Formula);
	})
	
	// 验算处理
	$(".Count").click(function(){
		var CountSymbol = $(this).attr("data-count");
		Formula = Formula+CountSymbol;
		$("#Countformula").html(Formula);
	})
	
	// 计算处理
	$(".Dispose").click(function(){
		var Dispose = $(this).attr("data-dispose");
		switch (Dispose){
			case "=":
				StartCount();
				break;
			case "B":
				Formula = Formula.substr(0,Formula.length-1);
				$("#Countformula").html(Formula);
				break;
			case "C":
				Formula ="";
				$("#Countformula").html(Formula);
				break;
			default:
				break;
		}
	})
	
	// 开始计算
	function StartCount(){
		//计算
		$("#Result").html(GetNumber(CountElement(Formula,0))+"=");
	}
	
	// 层次分割器(根据没被括号括起来的+-号分割层次),获得初始的分解块
	function LevelCT(CTCount,levelNumber){
		var addlevel = 0;			
		var SPS = 0;//切割的起始位置
		var CountList = [];
		
		for(var i = 0;i<=CTCount.length;i++){
			
			if(i==CTCount.length){
				//alert(CTCount.substring(SPS));
				CountList.push(CTCount.substring(SPS));
				break;
			}else if(addlevel==levelNumber){				
				if(CTCount.charAt(i)=="+"||CTCount.charAt(i)=="-"){
					//alert(CTCount.substring(SPS,i));
					CountList.push(CTCount.substring(SPS,i));					
					SPS = i;
				}
				
				if(CTCount.charAt(i)=="*"||CTCount.charAt(i)=="/"){
					CountList.push(CTCount.substring(SPS,i));
					SPS = i;
				}
			}
			
			if(CTCount.charAt(i)=="("){
				addlevel++;
			}
			if(CTCount.charAt(i)==")"){
				addlevel--;
			}
		}
		
		
		return CountList;
	}
	
	//获取数字
	function GetNumber(GetString){
		
		var input = GetString + "";
		var get = RegExp("\\d","g");
		
		var getnumber = input.match(get);
		
		return getnumber.join("");
	}
	
	
	//递归分解计算
	function CountElement(List,levelNumber){
		
		var Symbol = "NULL";
		var Sum = [];
		var SumNumber = 0;
		
		switch(List.charAt(0)){
			case "+":
				Symbol = "+";
			break;
			case "-":
				Symbol = "-";
			break;
			case "*":
				Symbol = "*";
			break;
			case "/":
				Symbol = "/";
			break;
		}
		
		if(Symbol!="NULL"){
			List = List.substr(1);
		}
		
		
		var CountFormulaUnit = LevelCT(List,levelNumber);//分解获取的参数,并进行分解
			
		
		//当该单元长度为1时,说明它无法再分解,是一个数字
		if(CountFormulaUnit.length == 1){
			var r = GetNumber(CountFormulaUnit)+(Symbol=="NULL"&&"|NULL"||"|"+Symbol);
			//document.write("分解:"+r);	
			return r;
		}else{
			//循环再分解的每一个单元
			//document.write("循环:"+CountFormulaUnit.join("&nbsp;&nbsp;&nbsp;&nbsp;")+"<br>");
			for(var i = 0;i<CountFormulaUnit.length;i++){
				var scanf = CountElement(CountFormulaUnit[i],levelNumber+1).split("|");
								
				switch (scanf[1]){
					case "+":
					case "-":
					case "*":
					case "/":
						Sum.push(scanf[1]);
						Sum.push(scanf[0]);
						break;	
					case "NULL":
						Sum.push(scanf[0]);
						// SumNumber = parseInt(scanf[0]);	
						break;																								
					default:
						break;
				}
			}
			
			//document.write("<br>增加:"+Sum.join(""))
			//执行乘除法
			var MADloca = GetMAD(Sum);
			while (MADloca!=-1){
				// 
				//根据计算符号记号
				switch (Sum[MADloca]){
					case "*":
							var MADNumber = parseFloat(Sum[MADloca-1]) * parseFloat(Sum[MADloca+1]);
							Sum = SetUnit(Sum,MADNumber,MADloca);
						break;
					case "/":
							var MADNumber = parseFloat(Sum[MADloca-1]) / parseFloat(Sum[MADloca+1]);
							Sum = SetUnit(Sum,MADNumber,MADloca);
						break;						
					default:
						
						break;
				}
				
				MADloca = GetMAD(Sum);
			}
			
			//执行加减法
			var CSymbol = "NULL";
			if(Sum.length>=1){
				SumNumber = parseFloat(Sum[0]);
				for(var i = 1;i<Sum.length;i++){
					// 递增递减
					switch (Sum[i]){
						case "+":
							CSymbol = "+";
							break;
						case "-":
							CSymbol = "-";
							break;							
						default:
							switch (CSymbol){
								case "+":
									SumNumber += parseFloat(Sum[i]);
									CSymbol = "NULL";
									break;
								case "-":
									SumNumber -= parseFloat(Sum[i]);								
									CSymbol = "NULL";
									break;									
								default:
									break;
							}
							break;
					}
				}
			}
			
			var r = SumNumber+(Symbol=="NULL"&&"|NULL"||"|"+Symbol);
			return r;
		}
		
	}
	
	//1.操作的对象 2.插入的对象 3.插入的起始位置
	function SetUnit(Sum,IObjecgt,Sloca){
		var Asum = [];
		for(var i = 0;i<Sum.length;i++){
			if(i == Sloca){
				// 添加代替数组
				Asum.push(IObjecgt);
			}else if(i>Sloca-2&&i<Sloca+2){
				
			}else{
				Asum.push(Sum[i]);
			}
		}
		Sum = Asum;
		return Sum;
	}
	
	// 获取第一个乘除号的位置
	function GetMAD(CountList){
		var MPTION = CountList.indexOf("*");
		var DIVSION = CountList.indexOf("/");
		
		var MAD = -1;// 第一个乘除法的位置
		
		if(MPTION>DIVSION){
			MAD = (DIVSION!=-1&&DIVSION||MPTION);
		}else{
			MAD = MPTION;
		}
		//返回计算符号位置
		return MAD;
	}
}

写在最后

其实我也只是个初学者,在技术方面都是靠自学,基础非常薄弱,厚颜无耻自称老师实属在下脸皮厚.希望这篇浅薄的教程可以帮助一些在前端学习中有些迷茫的同学.学到一些有用的知识.
同时,希望朋友们能够在评论区指出我的错误.共同进步.
我是阿巴阿巴阿巴的潘某人,咱们评论区或者下篇博文再见.古德拜!
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值