JS简易计算器——代码优化

Posted shige720

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS简易计算器——代码优化相关的知识,希望对你有一定的参考价值。

  这里用一个简易计算器的案例,来说明代码的一种优化思路具体方法

结构和样式                                                            

  先放上该项目的html和CSS部分

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6     <meta http-equiv="X-UA-Compatible" content="ie=edge">
 7     <title>简易计算器</title>
 8     <style>
 9         body
10             background:#777777;
11         
12         section
13             width:500px;height:300px;
14             position:absolute;top:50%;left:50%;
15             margin-top:-150px;margin-left:-250px;
16             border:1px dashed black;
17             font-size:20px;
18         
19         p
20             text-align:center;
21             margin-top:50px;
22         
23         button
24             width:40px;height:40px;
25         
26     </style>
27 </head>
28 <body>
29     <section>
30         <p>
31             <input type="text" class="input_forward" value="0">
32             <span class="symbol">+</span>
33             <input type="text" class="input_backward" value="0">
34             <span>=</span>
35             <span class="result">0</span>
36         </p>
37         <p>
38             <button title="add">+</button>
39             <button title="subtract">-</button>
40             <button title="multiply">×</button>
41             <button title="divide">÷</button>
42         </p>
43     </section>
44 </body>
45 </html>

  效果图如下(关注的是实际应用效果,因此CSS样式不做太多调整):

  技术图片

 

第一步:实现计算器效果                                       

  最开始先实现效果,用最简单的思路即可(目的是先实现,先完成后完善):

  ①获取元素:这里大多元素都是有独立的class类名的(有些直接用标签名获取),可以直接用querySelectorquerySelectorAll(button按钮)获取

  ②封装函数:加减乘除,通过获取的元素value,计算后改变result的值,同时改变符号位

  ③绑定事件:给每一个button绑定事件,在点击时执行某一函数

  这里直接把结构、样式和行为分离,不在HTML标签内部添加JS事件,而是在script标签中绑定事件

  JS部分的代码如下:

 1 //获取所有元素
 2 var num_forward = document.querySelector(".input_forward"),
 3       num_backward = document.querySelector(".input_backward"),
 4       symbol = document.querySelector(".symbol"),
 5       result = document.querySelector(".result"),
 6       btns = document.querySelectorAll("button");
 7 //封装所有函数
 8 function addHandler()
 9     var num1 = num_forward.value,
10           num2 = num_backward.value;
11     symbol.innerText = "+";
12     result.innerText = +num1 + +num2;//这里是为了防止被当成字符串拼接
13 
14 function subtractHandler()
15     var num1 = num_forward.value,
16           num2 = num_backward.value;
17     symbol.innerText = "-";
18     result.innerText = num1 - num2;
19 
20 function multiplyHandler()
21     var num1 = num_forward.value,
22           num2 = num_backward.value;
23     symbol.innerText = "×";
24     result.innerText = num1 * num2;
25 
26 function divideHandler()
27     var num1 = num_forward.value,
28           num2 = num_backward.value;
29     symbol.innerText = "÷";
30     result.innerText = num1 / num2;
31 
32 //绑定事件
33 btns[0].onclick = addHandler;
34 btns[1].onclick = subtractHandler;
35 btns[2].onclick = multiplyHandler;
36 btns[3].onclick = divideHandler;

 

第二步:修改绑定事件的方法                                

  经过观察得知,其中的绑定事件相当于遍历了btns里的所有元素,因此绑定事件可以用循环来改写

  JS代码如下:

 1 //获取所有元素
 2 var num_forward = document.querySelector(".input_forward"),
 3       num_backward = document.querySelector(".input_backward"),
 4       symbol = document.querySelector(".symbol"),
 5       result = document.querySelector(".result"),
 6       btns = document.querySelectorAll("button");
 7 //封装所有函数
 8 function addHandler()
 9     var num1 = num_forward.value,
10           num2 = num_backward.value;
11     symbol.innerText = "+";
12     result.innerText = +num1 + +num2;//这里是为了防止被当成字符串拼接
13 
14 function subtractHandler()
15     var num1 = num_forward.value,
16           num2 = num_backward.value;
17     symbol.innerText = "-";
18     result.innerText = num1 - num2;
19 
20 function multiplyHandler()
21     var num1 = num_forward.value,
22           num2 = num_backward.value;
23     symbol.innerText = "×";
24     result.innerText = num1 * num2;
25 
26 function divideHandler()
27     var num1 = num_forward.value,
28           num2 = num_backward.value;
29     symbol.innerText = "÷";
30     result.innerText = num1 / num2;
31 
32 //用循环绑定事件
33 for(var i=0;i<btns.length;i++)
34     btns[i].onclick = function()
35         switch(this.title)
36             case "add":
37                 addHandler();
38                 break;
39             case "subtract":
40                 subtractHandler();
41                 break;
42             case "multiply":
43                 multiplyHandler();
44                 break;
45             case "divide":
46                 divideHandler();
47                 break;
48         
49     
50 

 

第三步:函数的提取和封装                                       

  进一步观察,可以发现加减乘除四个函数里都分成三个部分:

  ①改变符号位的符号

  ②计算得出结果

  ③把计算的结果赋值到结果区域

  因此把这三部分提出来,单独封装三个通用的函数,主要是为了减少函数内部的细节暴露便于阅读函数

  该部分修改后,JS代码如下:

 1 //获取所有元素
 2 var num_forward = document.querySelector(".input_forward"),
 3       num_backward = document.querySelector(".input_backward"),
 4       symbol = document.querySelector(".symbol"),
 5       result = document.querySelector(".result"),
 6       btns = document.querySelectorAll("button");
 7 //封装所有函数
 8 //计算用的函数
 9 function add(num1,num2)
10     return +num1 + +num2;
11 
12 function subtract(num1,num2)
13     return num1 - num2;
14 
15 function multiply(num1,num2)
16     return num1 * num2;
17 
18 function divide(num1,num2)
19     return num1 / num2;
20 
21 //修改符号位的函数
22 function changeSymbol(ele)
23     symbol.innerText = ele;
24 
25 //修改输出内容的函数
26 function changeResult(ele)
27     result.innerText = ele;
28 
29 function addHandler()
30     var num1 = num_forward.value,
31           num2 = num_backward.value;
32     changeSymbol("+");
33     changeResult(add(num1,num2));//这里是为了防止被当成字符串拼接
34 
35 function subtractHandler()
36     var num1 = num_forward.value,
37           num2 = num_backward.value;
38     changeSymbol("-");
39     changeResult(subtract(num1,num2));
40 
41 function multiplyHandler()
42     var num1 = num_forward.value,
43           num2 = num_backward.value;
44     changeSymbol("×");
45     changeResult(multiply(num1,num2));
46 
47 function divideHandler()
48     var num1 = num_forward.value,
49           num2 = num_backward.value;
50     changeSymbol("÷");
51     changeResult(divide(num1,num2));
52 
53 //用循环绑定事件
54 for(var i=0;i<btns.length;i++)
55     btns[i].onclick = function()
56         switch(this.title)
57             case "add":
58                 addHandler();
59                 break;
60             case "subtract":
61                 subtractHandler();
62                 break;
63             case "multiply":
64                 multiplyHandler();
65                 break;
66             case "divide":
67                 divideHandler();
68                 break;
69         
70     
71 

 

第四步:变量、函数模块化                                     

  目前为止,书写的JS代码中,存有太多的全局变量以及函数,观察可以发现,所有的元素都是最外部框架的子元素,因此可以用一个对象包裹起来

  同时,也可以用一个对象把功能近似的函数给包裹起来,用访问对象方法的方式来调用函数

  修改后的JS代码如下:

 1 //获取所有元素
 2 var section = document.querySelector("section");
 3 var calculatorEles = 
 4       num_forward :section.querySelector(".input_forward"),
 5       num_backward:section.querySelector(".input_backward"),
 6       symbol:section.querySelector(".symbol"),
 7       result:section.querySelector(".result"),
 8       btns:section.querySelectorAll("button")
 9 
10 //封装所有函数
11 //计算用的函数
12 var operation = 
13     add:function(num1,num2)
14         return +num1 + +num2;
15     ,
16     subtract:function(num1,num2)
17         return num1 - num2;
18     ,
19     multiply:function(num1,num2)
20         return num1 * num2;
21     ,
22     divide:function(num1,num2)
23         return num1 / num2;
24     
25 
26 //修改符号位的函数
27 function changeSymbol(ele)
28     calculatorEles.symbol.innerText = ele;
29 
30 //修改输出内容的函数
31 function changeResult(ele)
32     calculatorEles.result.innerText = ele;
33 
34 function addHandler()
35     changeSymbol("+");
36     changeResult(operation.add(calculatorEles.num_forward.value,calculatorEles.num_backward.value));//这里是为了防止被当成字符串拼接
37 
38 function subtractHandler()
39     changeSymbol("-");
40     changeResult(operation.subtract(calculatorEles.num_forward.value,calculatorEles.num_backward.value));
41 
42 function multiplyHandler()
43     changeSymbol("×");
44     changeResult(operation.multiply(calculatorEles.num_forward.value,calculatorEles.num_backward.value));
45 
46 function divideHandler()
47     changeSymbol("÷");
48     changeResult(operation.divide(calculatorEles.num_forward.value,calculatorEles.num_backward.value));
49 
50 //用循环绑定事件
51 for(var i=0;i<calculatorEles.btns.length;i++)
52     calculatorEles.btns[i].onclick = function()
53         switch(this.title)
54             case "add":
55                 addHandler();
56                 break;
57             case "subtract":
58                 subtractHandler();
59                 break;
60             case "multiply":
61                 multiplyHandler();
62                 break;
63             case "divide":
64                 divideHandler();
65                 break;
66         
67     
68 

 

第五步:OCP原则                                                    

  OCP原则,即开放封闭原则(Open Close Principle),大致上即开放接口封闭原有的代码(防止修改时原有代码损坏)

  到目前为止的代码,尚存在以下问题:

  ①switch语句,一般不使用switch,因为实际开发时很可能不给源代码,增删改查时无法在原有的switch内部修改

  ②每个button点击时触发的函数,实际上可以提取出来,直接放到for循环中(修改符号位可以识别button中的innerText,而具体调用的函数名称也在每个button的title里体现了)

  ③计算方法的问题,既然可以用button的innerText来识别符号位,那也可以用button的title来识别计算方法,并调用这个方法

  ④添加新方法的问题,类似于①,实际开发中,很可能不会提供源码,那如果需要添加新的计算方法,是无法深入到对象内部进行添加的,因此有必要写一个接口,留给未来添加新方法用

  特别注意:这里不适合直接给对象添加新属性来添加新方法,因为不知道对象内部是否已经有同名的属性

  综合以上,修改完成的JS代码如下:

 1 //获取所有对象
 2 var cal = document.querySelector("section");
 3 var calculatorEles = 
 4       input_first :cal.querySelector(".input_first"),
 5       input_second:cal.querySelector(".input_second"),
 6       symbol:cal.querySelector(".symbol"),
 7       result:cal.querySelector(".result"),
 8       btns:cal.querySelectorAll("button")
 9 ;
10 //让元素内所有元素绑定同一事件
11 function each(array,fn)
12     for(var i=0;i<array.length;i++)
13         fn(i,array[i]);
14     
15 
16 //变更符号位内容
17 function changeSymbol(ele)
18     calculatorEles.symbol.innerText = ele;
19 
20 //变更输出内容
21 function changeResult(put)
22     calculatorEles.result.innerText = put;
23 
24 //加减乘除(大函数中的小函数封装)
25 var operation = 
26     add:function (num1,num2)
27         return +num1 + +num2;
28     ,
29     subtract:function(num1,num2)
30         return num1 - num2;
31     ,
32     multiply:function(num1,num2)
33         return num1 * num2;
34     ,
35     divide:function(num1,num2)
36         return num1 / num2;
37     ,
38     //添加一个用来添加新方法的接口
39     addOperation:function(name,fn)
40         if(!this[name])
41             this[name] = fn;//只有当前对象里不含有这个名称的方法时,才会添加方法
42         
43         return this;
44     
45 
46 //运算函数
47 function operate(name,num1,num2)
48     if(!operation[name])
49         throw new Error("没有名为"+name+"的计算方法!");
50     
51     operation[name](num1,num2);
52 
53 each(calculatorEles.btns,function(index,ele)
54     ele.onclick = function()
55         changeSymbol(this.innerText);
56         changeResult(operate(this.title,calculatorEles.input_first.value,calculatorEles.input_second.value));
57     
58 );

 

第六步:?                                                             

  本案例还有可以继续改进的地方,例如用模块化对函数进行再次封装,添加键盘事件,对小数的计算进行改进,等等

以上是关于JS简易计算器——代码优化的主要内容,如果未能解决你的问题,请参考以下文章

js代码借助函数eval制作简易计算器

javascript的一个简易利率计算器+js图像显示 代码

手把手教你制作简易的计算器

性能优化总结

Spring-AOP

网站代码图片优化汇总