改造javascript中的parseInt方法

本文探讨了parseInt函数处理带前导零的字符串时的问题,并提出了一种解决方案。通过对parseInt函数的重定义,使其在处理单参数时调用parseFloat,而处理双参数时保持原有功能。
问题:
很久以前发生的问题不想再痛苦的回忆。
这次的问题很简单。两个月份比较的时候,因为月份是从字符串中抽取出来的, 于是用parseInt转换了一下。
结果parseInt("08")之后结果是 0
原因请参看以下《JavaScript高级程序设计》19~20页对 parseInt函数的讲解。

parseInt() 方法还有基模式,可以把二进制、八进制、十六进制或其他任何进制的字符串转换成整数。
基是由 parseInt() 方法的第二个参数指定的,所以要解析十六进制的值,需如下调用 parseInt() 方法:

var iNum1 = parseInt("AF", 16); //返回 175
//当然,对二进制、八进制甚至十进制(默认模式),都可以这样调用 parseInt() 方法:
//复制代码 代码如下:
var iNum1 = parseInt("10", 2); //返回 2
var iNum2 = parseInt("10", 8); //返回 8
var iNum3 = parseInt("10", 10); //返回 10
//如果十进制数包含前导 0,那么最好采用基数 10,这样才不会意外地得到八进制的值。例如:
var iNum1 = parseInt("010"); //返回 8
var iNum2 = parseInt("010", 8); //返回 8
var iNum3 = parseInt("010", 10); //返回 10


在这段代码中,两行代码都把字符 "010" 解析成一个数字。

第一行代码把这个字符串看作八进制的值,解析它的方式与第二行代码(声明基数为 8)相同。最后一行代码声明基数为 10,所以 iNum3 最后等于 10。

初试身手:
以前的解决方法是让大家都抛弃 parseInt函数,全部以parseFloat来替换。
但是作为人“孰能无忘”?
最好的办法莫过于保留parseInt的“形”,废了parseInt的“神”。
于是我想到了《JavaScript高级程序设计》87~88页关于“重定义已有方法”的说明。
3.6.2 重定义已有方法
就像能给已有的类定义新方法一样,也可重定义已有的方法。
如前一章所述,函数名只是指向函数的指针,因此可以轻易地使它指向其他函数。如果修改了本地方法,如 toString() ,会出现什么情况呢?

Function.prototype.toString = function() {
return "Function code hidden";
}
//前面代码完全合法,运行结果完全符合预期:
function sayHi() {
alert("你好!");
}
alert(sayHi.toString()); //输出"Function code hidden"

也许你还记得,第 2 章中介绍过 Function 的 toString() 方法通常输出的是函数的源代码。
覆盖该方法,可以返回另一个字符串(在这个例子中,返回 "Function code hidden " )。
不过, toString() 指向的原始函数怎样了呢?它将被无用存储单元回收程序回收,因为它被完全废弃了。
没能够恢复原始函数的办法,所以在覆盖原始方法前,存储它的指针比较安全,以便以后的使用。
你甚至可能在某种情况下在新方法中调用原始方法:
Function.prototype.originalToString = Function.prtotype.toString;
Function.prototype.toString = function () {
if(this.originalToString().length >100) {
return "Function too leng to display.";
} else {
return this.originalToString();
}

在这段代码中,第一行代码把对当前 toString() 方法的引

用保存在属性 originalTo- String 中。然后用定制的方法覆盖了 toString() 方法。
新方法将检查该函数源代码的长度是否大于 100 。
如果是,就返回错误消息,说明该函数代码太长,否则调用 originalToString() 方法,返回函数的源代码。

根据这个例子,只要照葫芦画瓢写一行
Global.prototype.parseInt = Global.prototype.parseFloat;
那么 parseInt函数真的就变成徒有其表,肚子里面干的却是parseFloat勾当的函数了。
但是,同时一个致命的问题点也摆在眼前。
那就是JavaScript中的Global对象,就跟神一样, 只是个概念。
说明请参见下面《JavaScript高级程序设计》70页关于 “内置对象”的说明。
Global对象是ECMAScript中最特别的对象,因为实际上它根本不存在。
如果尝试编写下面的代码,将得到错误:
var pointer = Global;
错误消息显示Global不是对象,但刚才不是说Global是对象吗?
没错。这里需要理解的主要概念是,在ECMAScript中,不存在独立的函数,所有函数都必须是某个对象的方法。
本书前面介绍的函数,如 isNaN()、isFinite()、parseInt()和parseFloat()等,看起来都像独立的函数。
实际上,它们都是 Global对象的方法。

于是,上网大查怎样获取Global对象,或怎么使用Global.prototype来改变 parseInt函数。
结果可想而知,神就是神,就连著名的“搜神网”Google也查不出来。
欲放弃之时,果然应了那句“死地而后生”。突然想到parseInt就像个全局函数一样,根本不用什么对象调用。
那是不是说,只要把上面那句改成 parseInt = parseFloat;就可以了?
果然,神,无处不在!!! 好用了!!!


深度考究:
问题基本上解决了。只有一点需要注意的,就是JavaScript加载出错的时候,后面的语句就不加载执行了。
所以这句一定要放在第一句执行。现在正好建一个 JavaScript通用方法库,要求以后每个页面必须引入该库文件。
所以这一句放在该JavaScript通用方法库的第一行,从此便可高枕无忧。
但是当我在为该段代码写注释,特别是列举如何应用时,发现如下代码的问题
alert(parseInt("010", 2)); //10
alert(parseInt("010", 8)); //10
alert(parseInt("010", 10)); //10
每一个处理的返回值都是10,也就是说可以处理二进制,八进制,十六进制的parseInt从此消失了。
如果说单个参数的parseInt惹出了不少麻烦,我们对于没有惹祸的两个参数的parseInt还是希望保留其特异功能的。
于是需要进一步的改进。
那么就要根据使用parseInt函数时,传递参数的个数来进行判断处理。
如果只有一个参数,那么就调用parseFloat返回结果。
如果有两个以上的参数,那么就调用parseInt两个参数的处理,返回结果。
这里判断参数个数用到arguments对象,参见《JavaScript高级程序设计》53~54页关于arguments对象的说明。
在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名 ,就能访问它们。
例如,在函数 sayHi() 中,第一个参数是 message。
用 arguments[0] 也可以访问这个值,即第一个参数的值(第一个参数位于位置 0,第二个参数位于位置 1,依此类推)。
因此,无需明确命名参数,就可以重写函数:
function sayHi() {
if (arguments[0] == "bye") {
return;
}
alert(arguments[0]);
}
// 于是就有了如下代码:
originalparseInt = parseInt;
parseInt = function (){
if(arguments.length == 1){
return parseFloat(arguments[0]);
} else {
return originalparseInt(arguments[0], arguments[1]);
}
}

这段代码里我们改造了 parseInt,让其通过参数个数的不同进行不同的处理。
用一个新的变量originalparseInt保留了parseInt的原型。
这样我们即便改造了parseInt,依然能通过保留的原型变量originalparseInt使用parseInt的原始功能。

返璞归真:
代码写到这本以为一切都OK了,却被人说彻底抹杀了parseInt函数对2进制,8进制的处理。
想想也是。处理的过于极端,只想着用parseFloat彻底替换掉讨厌的parseInt函数。
如果我们正的用到2进制或8进制的数字转换,还得用我们费劲保留的 parseInt函数的原型新变量originalparseInt。
其实我们的愿望很简单。
parseInt函数中只有一个参数的时候就想让它简单的处理10进制的转换,别再因为首位的0来产生一些头疼的bug。
当我们用到第二个参数,想让它处理2进制,8进制的时候,我还依然能用parseInt既存的功能。
于是有了下面最终的代码:
考虑到js文件体积的问题,尽量减少代码量。于是把 originalparseInt 换成了 $parseInt。
另外把超级长的内置对象名arguments直接换成了一个字母 a 这样该对象用了4次节省的代码量就非常可观了。


举一反三:
对parseInt函数的再造就完成了。
那么其实我们可以根据这次改造的经验,改造与parseInt具有类似的烦人特性的JavaScript方法。
譬如,escape,unescape 这种已经被 W3C组织不推荐使用的方法就可以用被推荐的方法替换掉

escape = encodeURI;
unescape = decodeURI;

那么基于这次的经验,今后遇到类似的问题就可以考虑到用这种乾坤大挪移的方法去解决了。
<think>嗯,用户现在想用Servlet技术改造一个猜数字游戏。首先,我需要理解现有的猜数字游戏的结构是怎样的,可能是一个简单的控制台应用或者基于其他技术的Web应用。用户希望将其转换为基于Servlet的Web应用,这样用户可以通过浏览器进行游戏。 首先,用户提到的引用内容中有关于Servlet配置的部分,比如引用1中的`<servlet>`和`<servlet-mapping>`配置,这可能涉及到如何在web.xml中配置Servlet,或者使用注解的方式。另外,引用3提到了通过`ServletListenerRegistrationBean`注册监听器,这可能是在Spring Boot环境中配置Servlet的方式,但用户可能更倾向于使用纯Servlet技术,所以可能需要区分是否需要结合Spring或其他框架。 接下来,用户的问题是如何使用Servlet技术重构猜数字游戏。我需要考虑几个方面:游戏的流程、前后端交互方式、数据的存储和会话管理。猜数字游戏通常包括生成随机数、用户输入猜测、比较猜测与目标数字、反馈结果等步骤。在Web环境中,用户通过表单提交猜测,服务器处理请求并返回结果。 首先,需要设计前端页面,可能包括输入框和提交按钮,显示历史猜测和结果。然后,后端Servlet需要处理GET和POST请求,生成目标数字(可能需要存储在会话中),验证用户输入,比较数字,并更新游戏状态。 考虑到用户之前的问题涉及部署错误,可能需要提醒用户注意Servlet的配置是否正确,比如URL映射、注解或web.xml的设置,避免出现404错误。同时,会话管理是关键,因为每个用户的游戏状态需要独立保存,可以使用HttpSession来存储目标数字和猜测次数。 另外,用户可能在代码中需要处理异常情况,比如非数字输入、范围外的数字等,需要在前端或后端进行验证,并给出相应的提示信息。此外,是否需要限制猜测次数,或者在猜中后提供重新开始的选项,这些功能都需要考虑。 在代码示例中,需要展示如何创建Servlet类,处理请求参数,访问和修改会话属性,生成响应HTML页面。同时,可能需要使用JSP或者纯HTML,但用户提到使用Servlet技术,所以可能倾向于在Servlet中生成HTML输出,或者结合JSP视图。 还需要考虑Web应用的部署结构,确保Servlet类正确放置在WEB-INF/classes目录下,web.xml配置正确,或者使用注解配置Servlet的URL路径。用户之前的问题中提到了Artifact配置和依赖管理,可能需要确认项目是否包含必要的Servlet API依赖,比如javax.servlet-api,并且作用域设置为provided,避免部署冲突。 可能的问题点包括:会话管理是否正确,Servlet生命周期处理是否合理,线程安全问题(例如,Servlet是否是线程安全的,是否需要同步部分代码),以及输入验证是否充分。此外,用户可能需要考虑如何美化前端界面,使用CSS或JavaScript增强用户体验,但这可能超出当前问题的范围。 总结来说,步骤大致如下: 1. 设计前端页面,包含输入表单和结果显示区域。 2. 创建Servlet处理用户提交的猜测,生成和存储目标数字,管理会话。 3. 配置Servlet的URL映射,确保正确响应请求。 4. 处理用户输入,验证有效性,比较数字,更新游戏状态。 5. 生成动态响应页面,显示历史记录和结果。 6. 测试部署,确保Servlet正确运行,处理各种异常情况。 可能还需要考虑如何在没有JSP的情况下生成动态内容,比如通过Servlet的PrintWriter输出HTML字符串,或者使用模板引擎。但根据用户的技术栈,保持简单,使用Servlet内嵌HTML可能是更直接的方法。 最后,需要确保提供的代码示例正确,包括必要的导入、注解配置或web.xml配置,并解释关键部分,帮助用户理解实现细节。同时,提醒用户注意常见的部署错误,如依赖缺失、配置错误、路径问题等,参考之前的问题解决方案。</think>### 分步解决方案:使用Servlet技术改造猜数字游戏 #### 1. **定义游戏核心逻辑** - **目标数字生成**:使用`java.util.Random`生成1-100的随机数,存储在`HttpSession`中实现状态保持[^1]。 - **输入验证**:通过`request.getParameter()`获取用户输入,并校验是否为有效整数。 ```java // 从Session获取目标数字 HttpSession session = request.getSession(); Integer target = (Integer) session.getAttribute("target"); // 生成新游戏(若Session中不存在目标数字) if (target == null) { target = new Random().nextInt(100) + 1; session.setAttribute("target", target); session.setAttribute("attempts", 0); } ``` #### 2. **创建Servlet处理请求** - **注解配置**:使用`@WebServlet`定义访问路径(或通过`web.xml`配置[^1])。 ```java @WebServlet("/guess") public class GuessNumberServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { // 处理用户猜测 } } ``` #### 3. **实现请求处理逻辑** - **参数解析与比较**: ```java String guessStr = request.getParameter("number"); try { int guess = Integer.parseInt(guessStr); int attempts = (int) session.getAttribute("attempts") + 1; session.setAttribute("attempts", attempts); String result; if (guess == target) { result = "猜中了!目标数字是" + target + ",共尝试" + attempts + "次"; session.invalidate(); // 重置游戏 } else if (guess > target) { result = "猜大了!"; } else { result = "猜小了!"; } response.getWriter().write(generateHtml(result)); } catch (NumberFormatException e) { response.getWriter().write(generateHtml("请输入有效数字")); } ``` #### 4. **生成动态HTML响应** - **内联HTML构造**:直接在Servlet中拼接HTML内容(或使用JSP)。 ```java private String generateHtml(String message) { return "<html><body>" + "<h2>猜数字游戏(1-100)</h2>" + "<form method='post'>" + "<input type='number' name='number' min='1' max='100' required>" + "<button type='submit'>提交</button>" + "</form>" + "<p>" + message + "</p>" + "</body></html>"; } ``` #### 5. **配置部署环境** - **依赖管理**:确保`pom.xml`包含Servlet API依赖(非Spring Boot项目): ```xml <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> ``` - **部署到Tomcat**:将项目打包为WAR文件并部署,或使用`mvn tomcat7:run`直接运行[^1]。 --- ### 相关问题 1. **如何通过`HttpSession`实现用户登录状态管理?** 2. **Servlet中如何处理文件上传功能?** 3. **如何用JSP替代Servlet内嵌HTML实现视图分离?** --- ### 关键改进点说明 1. **会话保持**:通过`HttpSession`存储游戏状态,避免每次请求重置进度[^1]。 2. **输入验证**:捕获`NumberFormatException`防止非数字输入导致崩溃。 3. **线程安全**:Servlet实例默认单例,但`HttpSession`天然隔离用户数据,无需额外同步。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值