JavaScript - 如果...没有方法(xjl456852修改)
本文是对下面这篇文章中存在的错误进行修改,并增加少量注释.
原文出处:
JavaScript - 如果...没有方法
http://www.cnblogs.com/silin6/p/4367019.html
这篇文章源于我上一周所读的一篇12年的文章。原作者提出了一个问题,如果js没有原生方法Math.round(),我们如何去实现呢?
对此我和我的基友进行了小小探讨,并给出了一些有意思的答案。
本文内容如下:
- 如果...没有方法
- 解决方案
- 另类解决方案
- 简单的分析
- 参考和引用
JavaScript - 前端开发交流群:377786580
如果...没有方法
这篇文章源于上周所读的一篇2012年的文章(为了强行塞点文章篇幅,所以把该文链接放到最后的引用了...希望原作者和读者体谅下....)。
原作者在使用了Math.round()方法之后,突然产生了一个小念头。
如果,js没有
Math.round()方法,我们又该如何去实现呢?
为此展开了一些探讨。我知道发表这么一篇文章肯定小有争议,但仍需要注明的是这篇文章仅供娱乐,或者说——玩玩代码,不会太在意性能、健壮、逻辑严谨性等XXOO的东西。Math.round()就是传说中的四舍五入啦...
Math.round(12.1);//12
Math.round(12.8);//13
Math.round(-12.1);//-12
Math.round(-12.8);//-13
解决方案
原作者提供了这么些思路:
例如数字
6.2,先把6.2转换为字符串,然后通过String.prototype.split()方法来分割字符串,判定字符串索引为1的值是否大于5,再处理索引为0的值,代码如下:
//num===6.2
function round(num) {
var nums = String(num).split("."),//[6,2]
num0 = nums[0],//6
num1 = nums[1];//2
if (parseInt(num1.substring(0, 1)) < 5) { //2<5
return parseInt(num0);
} else {
if (num0 > 0) {
return parseInt(num0) + 1;
} else {//负数
return parseInt(num0) - 1;
}
}
}
原作者并不满意上面的解决方案,提出了如果连js原生方法都不使用呢?什么String()、parseInt()都不使用该怎么去做呢?
于是提出了第二种解决方案:
这个问题的关键在于判定小数点后的数字是否大于5,所以我们把传递进来的数字
6.2*10%10即可得到小数点后的数字,这时候再判定这个小数是否大于5即可。
//num===6.2
function round(num) {
var round_x = (((10 * num) % 10) > 0) ?
((10 * num) % 10) : //正数
-((10 * num) % 10);//负数
if (round_x < 5) {
return num - (num % 1);//把小数点后的的数字干掉
} else {
return (num > 0 ?
(num - (num % 1) + 1) : //正数
num - (num % 1) - 1); //负数
}
}
原文只讲述到这里,后来我跟基友聊到了这篇文章,我的基友给出了另外一点思路:
因为是四舍五入原理,所以给当前的数字+0.5,得到的值直接丢弃小数点后面的部分转换为整数(类似parseInt),原来的数字也转换为整数丢弃小数点后面的部分,这两个数如果相差<1,表示取原来数字的整数,否则取新数字的整数。
function round(num) {
var value = num > 0 ?
num + 0.5 : //正数
-(num - 0.5); //负数
value = value - value % 1;//得到新数的整数部分
//如果相差<1
return value - num < 1 ?
num - num % 1 :
value;
}
至此,稍微正常点的解决方案介绍完毕,下面我们来感受下什么叫做玩代码。
另类解决方案
听到基友的思路我表示非常赞非常好人民需要你代码需要你下一个图灵目测就是你了小伙子要不要买本《颈椎病康复指南》看看决定如何拯救世界?
然后给他感受了一下这个世界森森的恶意——也就是原文评论里的代码。
下面是欣赏代码时间,分析代码之类的肯定要放在后面。
//@Gray Zhang的"给跪版",不支持负数
function round(x) {
return ~~(x + 0.5);
}
//@Gray Zhang的"给跪加深版",支持正负数
function round(x) {
return ~~(x > 0 ? (x + 0.5) : (x - 0.5));
}
//@强子~Developer的"请收下我的膝盖版"
function round(x) {
return (x > 0 ? x + 0.5 : x - 0.5) | 0;
}
看到这些代码当时我就给跪了,突然有种回家找家影楼给别人撒撒花,扬扬裙摆,送送快递的想法。好吧,我承认我的位运算就是个渣。
当然,你以为我们的思考仅限于此?no no no,我们觉得用这些什么if、else、三目运算符实在太low,于是我和基友想:如果连这些运算符都给干掉呢?只通过位运算来实现。
在各种恶补位运算的知识下,我的基友提出了另外一种解决方案:(xjl456852修改)
修改原因:
右移必须是31位才行,30位是错误的.-2147483648 >>30 你这个移动30就是-2不是-1, 移动31位才是-1.
function round(x) {
return ~~(x + 0.5 + (x >> 31));
}
简单的分析
觉得上面的代码逼格十足?那么让我们"粗略"的分析一下吧(详细计算、补码之类的知识请拉到参考引用)。
这些代码都运用了位运算——我们重点关照下~(按位取反运算)和>>(有符号右偏移运算)。
首先,偷点基础资料来:
重温整数
ECMAScript 整数有两种类型,即有符号整数(允许用正数和负数)和无符号整数(只允许用正数)。在 ECMAScript 中,所有整数字面量默认都是有符号整数。
有符号整数使用有 31 位表示整数的数值,从第1位开始数,第 32位表示整数的符号(下图是从第0位开始数,有些区别),0 表示正数,1 表示负数。数值范围从 -2147483648 到 2147483647。见下图:
因为样式的原因图片会存在拉伸,看不清请拿鼠标拽一下图片到新的浏览器标签页即可。

js中toString()方法可以to出二进制,而parsetInt()方法的第二个参数可以指定转换进制:
(18).toString(2) //"10010"
parseInt(10010,2) //18
~的运算过程
~就是按位取反,类似:00111,取反则为11000。
取反会干掉小数,~运算符的运算过程可以戳这里,我们看到调用了ToInt32():

所以会被干掉小数,所以我们可以这么来实现小数转整数:
~~18.5 //18 - 等同于parseInt(18)
parseInt(18.5) //18
~~是按位取反再取反,本质上就是一个干掉小数的过程。
>>有符号右移运算符
>>是有符号右移运算符由两个大于号表示(>>)。它把 32 位数字中的所有数位整体右移,同时保留该数的符号(正号或负号)。有符号右移运算符恰好与左移运算相反。
我们来解析一下这段代码:
-2>>31 // -1 (感谢群里的@Superior和@Jeff Xiao提供)
过程如下:
- 1 1111111111111111111111111111110 //-2的二进制(负数以补码进行存储)
- 1 1111111111111111111111111111111 //向右移动31,高位以符号位(第32位)补全,结果为-1
我们再来看看我的基佬提供的代码:
~~(x + 0.5 + (x >> 31))
- 假设X是-12.5
- 首先,-12.5+0.5===-12
- -12.5>>31:上面我们说过,ECMAScript有符号整数使用
31位表示整数的数值,所以在ECMAScript中,任何一个数右移31位得到的结果只能是2种:正数得到0,负数得到-1。- -12-1===-13
由此完成了我们的运算,不得不说这个+0.5和>>31很是精髓(虽然我基佬也是查了半天资料才搞出来 = =)。
再次声明,这篇文章和代码,纯属娱乐。对于上面看的迷迷糊糊,位运算之类的东西还搞不明白的童鞋可以看看下面的参考。
代码总是很有意思的,没事玩玩代码放松一下自己也是好的,顺便还可以涨姿势,何乐而不为呢?顺便说一下,我和基佬商量着以后要是当了面试官就准备这个问题问一下别人——当然,只是娱乐娱乐。再次感谢群里的@Superior和@Jeff Xiao为我细心的讲解。
最后,向原文和前辈致敬:《JS,如果没有方法。。。(不借助任何JS方法实现round方法)》。
JavaScript - 前端开发交流群:377786580
JavaScript - 如果...没有方法(xjl456852修改)的更多相关文章
- javascript数组原型方法
1.javascript数组原型方法. <!DOCTYPE html> <html lang="en"> <head> <meta cha ...
- 深入了解javascript的sort方法
在javascript中,数组对象有一个有趣的方法 sort,它接收一个类型为函数的参数作为排序的依据.这意味着开发者只需要关注如何比较两个值的大小,而不用管“排序”这件事内部是如何实现的.不过了解一 ...
- javaScript面向对象继承方法经典实现
转自原文javaScript面向对象继承方法经典实现 JavaScript的出现已经将近20多年了,但是对这个预言的褒贬还是众说纷纭.很多人都说JavaScript不能算是面向对象的变成语言.但是Ja ...
- javascript创建对象的方法--动态原型模式
javascript创建对象的方法--动态原型模式 一.总结 1.作用:解决组合模式的属性和函数分离问题 2.思路:基本思路和组合模式相同:共用的函数和属性用原型方式,非共用的的函数和属性用构造函数 ...
- javascript创建对象的方法--原型模式
javascript创建对象的方法--原型模式 一.总结 1.原型模式解决内存浪费的方法(继承):通过继承,对象继承原型模式下的所有属性,对象不同于其它对象的的属性自己创建或者修改 2.原型的使用(p ...
- JavaScript Array 数组方法汇总
JavaScript Array 数组方法汇总 1. arr.push() 从后面添加元素,返回值为添加完后的数组的长度 var arr = [1,2,3,4,5] console.log(arr.p ...
- javascript 元编程之-代码修改代码
javascript 元编程之-代码修改代码 引言 重构代码是个体力活,特别是在确定重构方案后,剩下就是按方案调整代码,然后进行测试. 如何有好又快的调整到位代码,这是件不容易的事. 简单的代码,可以 ...
- Javascript对象的方法赋值
Javascript对象编程学习中,一直不能很好的掌握对象的属性(property)和方法(method).今天在写代码过程中,又犯了一个低级错误. <!DOCTYPE html> < ...
- JavaScript中reduce()方法
原文 http://aotu.io/notes/2016/04/15/2016-04-14-js-reduce/ JavaScript中reduce()方法不完全指南 reduce() 方法接收 ...
随机推荐
- python中threading模块中的Join类
join类是threading中用于堵塞当前主线程的类,其作用是阻止全部的线程继续运行,直到被调用的线程执行完毕或者超时.具体代码如下: import threading,time def doWai ...
- bootstrap 弹出框 另类运用
下面是我在做一个简单登录页面时,应用boostrap弹出框,通过调节做成警示框的过程,前后经过了一番波折.因为摸索过程十分有趣,最后也是成功的,使用弹出框做除了警示框的效果,下面我们来看一下吧. 首先 ...
- SpringBoot使用MongoDB
一.什么是MongoDB MongoDB是一个基于分布式文件存储的数据库,由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB是一个介于关系数据库和非关系数据库之间的 ...
- Unix\Linux | 总结笔记 | 邮件发送
实验:在本地实现不同用户收发邮件 #root发送邮件 #stu 收邮件 #stu 查看邮件 并回复邮件 #root 查看stu回复的邮件
- [AHOI2007]密码箱
Description 在一次偶然的情况下,小可可得到了一个密码箱,听说里面藏着一份古代流传下来的藏宝图,只要能破解密码就能打开箱子,而箱子背面刻着的古代图标,就是对密码的提示.经过艰苦的破译,小可可 ...
- Python variable 作用域和初始化
Python 根据LEGB rule在不同的namespace中找变量 在def的函数中对global 变量做修改还是不推荐的,应该将其作为参数传入函数 try: do_something() cnt ...
- OpenCV2.4.9 + Ubuntu15.04配置
为了run Car-Detection安装了OpenCV. 基本上就照着这个弄下来: ubuntu14.04 + OpenCV2.4.9 配置方法 1. 安装openCV 所需依赖库或软件: s ...
- 奇葩问题: lsattr -d /data 显示:----------I--e- /data/
奇葩问题 lsattr -d /data 显示:----------I--e- /data/ 问题影响: 其他权限中I(大写i) 目录下不能删除文件,不能添加文件 ================== ...
- 转】[MySQL优化]为MySQL数据文件ibdata1瘦身
原博文出自于: http://blog.fens.me/category/%E6%95%B0%E6%8D%AE%E5%BA%93/page/2/ 感谢! [MySQL优化]为MySQL数据文件ibda ...
- yii在Windows下安装(通过composer方式)
Composer 安装: (Composer 不是一个包管理器,它仅仅是一个依赖管理工具.它涉及 "packages" 和 "libraries",但它在每个项 ...