再谈js的位运算

前言

前几天无意中看到一段话:

位运算符针对的是整数,所以对javascript完全无用,因为javascript内部,所有的数字都保存为双精度浮点数。如果使用它们的话,javascript不得不将运算数先转为整数,然后再进行运算,这样就降低了速度。而且”按位与运算符” & 同”逻辑与运算符” && ,很容易混淆。

出自某前辈很久前的一篇博文,查了下ECMAScript 标准,说得大致没错。但是刚好自己上一篇博文里总结了一些位运算技巧,忍不住多思索了一下,撇开容易混淆不谈,js中的位运算具体会慢多少呢?接下来请收看好奇的鳗鱼宝宝的探索之旅。

普通运算 vs 位运算

还是就之前文章的例子:

1
2
3
4
5
6
var arr = [],
len = 9999999;
for (var i = 0; i < len; i++) {
// arr[i] = i % 4;
arr[i] = i & 3;
}

扔浏览器中运行一番,可以看到script运行的时间为4774.5ms
位运算
改为正常的运算i % 4
位运算
相差不是很大,而且似乎并没有验证出上文中指出会拖慢的观点。于是循环量加大一位数,循环长度为99999999,继续测试,并且提高样本数量为20,得出以下结果

- 第1次 第2次 第3次 第4次 第5次 第6次 第7次 第8次 第9次 第10次 第11次 第12次 第13次 第14次 第15次 平均
i & 3 4225.1 4103.5 4021.5 2291.6 4742.8 4123.5 4270.6 4303.1 3998.7 4380.5 4122.3 3936.4 4178.9 4349.7 4128.0 4078.413
i % 4 4531.6 4238.8 4343.5 4493.2 4095.1 4341.4 4437.9 5059.3 4224.0 4211.4 5011.1 4211.4 4193.9 4253.7 4271.4 4394.513

另外,对其他常见的运算也做了一定的实验。
循环数定为9999999,样本数量为10,去掉最高和最低的数据之后的平均值如下:

具体数据参见:

总结

最后,花了一个下午来做实验,不知道是不是因为样本数量不够还是统计分析建立的模型有错之类的什么原因,并没有完全的证实出javascript使用位运算会降低速度的结论。以后可以再研究下顺便复习复习统计学什么的。总之,印证了一个道理,我们没要必要排斥在 JS 中使用位运算。一方面对于整数,例如取反等的确比较好用,通常项目里不会产生测试例子那么庞大的循环性能影响也不会很大。不过不要为了装逼秀技大量使用从而影响阅读性就好。(比如用用void 0代替undefined

最后的最后,祭出Angular中一段使用到了位运算的挺有意思的源码。主要用来处理字母大小写转换(由于某些国家例如土耳其使用 toLowerCase()toUpperCase() 不能正确的转换字母大小写,需要手动的处理)

1
2
3
4
5
6
7
8
9
10
var manualLowercase = function (s) {
return isString(s) ? s.replace(/[A-Z]/g, function(ch) {
return String.fromCharCode(ch.charCodeAt(0) | 32)
}) : s
}
var manualUppercase = function (s) {
return isString(s) ? s.replace(/[a-z]/g, function(ch) {
return String.fromCharCode(ch.charCodeAt(0) & ~32)
}) : s
}

参考资料:

  1. JavaScript 数据类型和数据结构