underscore.js库
你一天(一周)内写了多少个循环了?
var i;for(i = 0; i < somearray.length; i++) { var something = somearray[i]; dosomeworkon(something);}
这当然无害,但这种写法非常丑而且奇怪,这也不是真正需要抱怨的。但这种写法太平庸了。
var i, j;for(i = 0; i < somearray.length; i++) { var something = somearray[i]; for(j = 0; j < something.stuff.length; j++) { dosomeworkon(something.stuff[j]); }}
你在扩展糟糕的代码,在你抛出一大堆if前,你已经精神错乱了。
我在两年里没有写一个循环(loop)。
“你在说什么?”
这是真的,一个冷笑话。其实不是一个都没有(好吧,我确实写了几个),因为我不写循环(loops),我的代码更容易理解。
怎么做的呢?
_.each(somearray, function(something) { dosomeworkon(something);})
或者更好一点:
_.each(somearray, dosomeworkon);
这就是underscorejs所做到的。干净,简单,易读,短,没有中间变量,没有成堆的分号,简单非常优雅。
这是另外一些例子。
var i, result = [];for(i = 0; i < somearray.length; i++) { var something = somearray[i]; // 打到这,我已经手疼了 if(something.isawesome === true) { result.push(somearray[i]); }}
同样,一个使用循环浪费时间的典型用例。即便这些网站是宣传禁烟和素食主义的,看到这些代码我也感到义愤。看看简单的写法。
var result = _.filter(somearray, function(something) { return something.isawesome === true;})
像underscore中的filter(过滤)的名字那样,随手写的3行代码就可以给你一个新的数组(array)。
或者你想把这些数组转换成另外一种形式?
var result = _.map(somearray, function(something) { return trasformthething(something);})
上面三个例子在日常生活中已经够用了,但这些功能还不足矣让underscore放到台面上。
var grandtotal = 0, somepercentage = 1.07, severalnumbers = [33, 54, 42], i; // don't forget to hoist those indices;for(i = 0; i < severalnumbers.length; i++) { var anumber = severalnumbers[i]; grandtotal += anumber * somepercentage;}
underscore版本
var somepercentage = 1.07, severalnumbers = [33, 54, 42], grandtotal;grandtotal = _.reduce(severalnumbers, function(runningtotal, anumber) { return runningtotal + (anumber * somepercentage);}, 0)
这个刚开始看上去可能有点怪,我查了下关于reduce的文档,知道了它的存在。因为我拒绝使用循环,所以它是我的首选。上面这些东西仅仅是入门,underscorejs库还有一大堆牛b的功能。
30天不使用循环的挑战。
在一下一个30天里,不要使用任何循环,如果你看到一堆讨厌和粗糙的东西,用each或者map将他们替换掉。再用一点reducing。
你需要注意到,underscore是通往函数式编程的。一种看得见,看不见的方式。一条很好的途径。
ourjs注*目前现代浏览器已经支持each, filter, map, reduce方法,但underscore库可以实现对旧版ie的兼容,下面是使用es5原生方法写的例子:
[3,4,5,3,3].foreach(function(obj){ console.log(obj);});[1,2,3,4,5].filter(function(obj){ return obj < 3});[9,8,5,2,3,4,5].map(function(obj){ return obj + 2;});[1,2,3,4,5].reduce(function(pre, cur, idx, arr) { console.log(idx); //4 个循环: 2-5 return pre + cur;}); //15//sort方法同样很有用[9,8,5,2,3,4,5].sort(function(obj1, obj2){ return obj1 - obj2;});
for in与for loop
有人提出for in的效率要比for loop(循环)的效率低非常多。现在我们测试一下在不同浏览器中使用for in, for loop和foreach在处理大数组时的效率究竟如何。
目前绝大部分开源软件都会在for loop中缓存数组长度,因为普通观点认为某些浏览器array.length每次都会重新计算数组长度,因此通常用临时变量来事先存储数组长度,如:
for (var idx = 0, len = testarray.length; idx < len; idx++) { //do sth.}
我们也会测试一下缓存与不缓存时的性能差异。
同时在每个测试循环中添加求和运算,来表明其不是空循环。
for (var idx = 0, len = testarray.length; idx < len; idx++) { //do sth.}
我们也会测试一下缓存与不缓存时的性能差异。
同时在每个测试循环中添加求和运算,来表明其不是空循环。
测试代码如下,点击运行即可查看
html 代码
javascript 代码
function () { //准备测试数据, 有200万条数据的大数组 var testarray = [] , testobject = {} , idx , len = 2000000 , tmp = 0 , $results = $(#results) , $browser = $(#browser) ; $browser.html(navigator.useragent); $results.html(''); for (var i = 0; i < len; i++) { var number = math.random(); //若希望加快运算速度可使用取整:math.random() * 10 | 0 testarray.push(number); testobject[i] = number; } $results.append('测试代码计算结果所需时间,毫秒
'); //测试函数 var test = function(testfunc) { var starttime , endtime , result ; starttime = new date(); tmp = 0; testfunc(); endtime = new date(); //计算测试用例(test case)运行所需要的时间 result = endtime - starttime; $results.append('{0}
{1} {2}
'.format(testfunc.tostring(), tmp | 0, result)); }; test(function() { //测试for in 的效率 for (idx in testarray) { tmp += testarray[idx]; //经测试,idx是string类型,可能是慢的原因之一 } }); test(function() { //测试for loop循环的效率 for (idx = 0, len = testarray.length; idx < len; idx++) { tmp += testarray[idx]; } }); test(function() { //测试foreach的效率 testarray.foreach(function(data) { tmp += data; }); }); test(function() { //测试不缓存array.length时效率 for (idx = 0; idx < testarray.length; idx++) { tmp += testarray[idx]; } }); test(function() { //测试使用{} (object) 存健值对时,使用for in的效率如何 for (idx in testobject) { tmp += testobject[idx]; } }); test(function() { //测试从{} object查值时的效率如何(这里的健key值事先己知) for (idx = 0, len = testarray.length; idx < len; idx++) { tmp += testobject[idx]; } });}
运行 [需稍等片刻]
测试结果
测试结果可能因计算而异,这是在我机器上运行用,firefox, chrome, ie三者测试结果拼接的一张汇总。
以下是几个观察到的结论
for in比for loop慢非常多,在chrome中至少慢20倍 ff对foreach(es5)做了优化,性能比for loop还要好一点,但chrome/ien性能均较差 ff/chrome缓存array.length均比直接用时要慢一点。除ie最新版缓存后性能提升微乎其微(这一点非常意外) 在某些情况下,ff的js引擎性能似乎比v8要好些