再谈javascript的for循环性能
来源:互联网 发布:apache bench windows 编辑:程序博客网 时间:2024/05/17 00:17
前几天又温习了一番JS的基础知识,发现JS循环同其他语言的循环大有不同,随后再继续翻了俩本JS的权威教程,写下这篇文章。
平时我们书写循环大致是这个样子的:
function
(){
//一般循环的书写方式
for
(
var
i=0; i<values.length; i++){
...
}
}
优化变量声明
上面这个写法在一开始学习JS的时候是没有错的,甚至对于绝大多数的面向对象语言这么写都是正确的书写方式,但JS不同与其他面向对象的语言,他没有块及作用域,有的仅仅是函数作用域,所以说,上面的写法并不是很规范,在某些情况下还会发生Bug ,当你使用了一个变量,然后不久在函数中又重新声明的话,就可能产生逻辑错误。对于JavaScript,只要你的变量是在同一个作用域中(同一函数),它都被当做是声明的,即使是它在var声明前使用的时候。合理的写法即把变量声明在函数的开始,而不是在循环内部才开始定义变量。
function
func(){
//优化JS的变量定义,变量定义在开始位置,避免产生块级作用域的误区
var
i;
for
(i=0; i<values.length; i++){
...
}
}
优化循环中动态集合读取
优化了JS 循环的变量后,我们继续深入优化。日常开发最常打交道的就是DOM 了,常常会遇到循环NodeList 的情况(不知道什么是NodeList 对象的话请去复习基础知识)。总而言之一般类似var divs = document.getElementsByTagName(“div”) 的这个divs 所引用的就是NodeList 对象,其他类似的NodeList 近亲有NameNodeMap 和 HTMLCollection, 这三个集合每当文档结构发生变化时,它们都会得到更新(而且还是动态的更新)。这样就会导致俩个问题,第一是性能问题,每当你修改NodeList 在读取它时,你读取的不是先前的NodeList 而是修改后动态更新的NodeList。第二会产生无限循环的Bug。举个例子,下列代码会导致无限循环:
function
func(){
//导致NodeList无限循环的循环书写方式
var
divs = document.getElementsByTagName(
"div"
);
for
(
var
i=0; i<divs.length; i++){
var
div =document.createElement(
"div"
);
document.body.appendChild(div);
alert(
"Infinite loop"
);
}
}
func()
上例所示的循环代码会导致一个严重的问题,每次循环都要对divs.length 求值,意味着会运行取得所有div元素的查询,之后创建一个新的div元素添加的文档中,因此div.length 的值每次循环后都会递增。既然i 和divs.length 每次都会同时递增,结果他们的值永远不会相等,从而导致了无限循环。
为了避免出现这样的低效率甚至于隐含Bug的循环书写方式,对策就是尽量减少访问NodeList 的次数。因为每次访问NodeList,都会运行一次基于文档的查询。所以可以考虑从NodeList 中取得的值缓存起来。下面是优化后的写法:
function
func(){
//避免NodeList无限循环的循环书写方式
var
divs = document.getElementsByTagName(
"div"
);
for
(
var
i=0, len = divs.length ; i<len; i++){
var
div =document.createElement(
"div"
);
document.body.appendChild(div);
alert(
"Infinite loop will not happen"
);
}
}
func()
很简单吧,只要把divs.length 缓存起来放在一个变量len 里面,那么无论NodeList以后怎么变,都避免读取,避免无限循环发生,因为JavaScript的解释性,所以a.b.c.d.e,需要进行至少4次查询操作,先检查a再检查a中的b,再检查b中的c,如此往下。所以如果这样的表达式重复出现,只要可能,应该尽量少出现这样的表达式,利用局部变量,把它放入一个临时的地方进行查询。如果每次查询div.length,就要额外进行一个操作,而预先把var len=div.length,则就少了一次查询,性能的优化大大体现。 开始你会觉得这样书写很不适应,但多写几遍,你很快就会习惯这样“别扭”书写方式的。
优化继续优化!
用i+=1 代替i++
这个是从《Javascript语言精粹》里面看来的,大致意思是说用了i++ 会有潜在的安全问题,++这个运算符可以前置又可以后置使得自由度过大,如果出现结尾没有分号会导致些许的错误例如:a++b++c,你很难弄明白前面那个代码是什么意思。根据《Javascript语言精粹》上面提到,这个++ 或者–– 运算符怂恿过于诡异的写法而促使出现糟糕的代码。除了错误的架构外,它们是导致病毒和其他安全威胁的第二大元凶。所以JsLint有个选项plusplus 是检测是否禁止使用了这些运算符。还有个原因是i+=1 比起i++ 更加“原生”可以提升性能,但是个人认为可读性降低,根据需要各自取舍吧。那么我们的代码又要变成这个样子:
function
func(){
//用i+=1 代替i++
for
(
var
i=0; i<values.length; i+=1){
...
}
}
让优化来的更猛烈些吧!
减值迭代优化循环
大多数循环使用一个从0开始、增加到某个特定值的迭代器。在很多情况下,从最大值开始,在循环中不断减值的迭代器更加高效。如果值的处理顺序无关紧要,那么循环可以改为i 减值,优化如下:
function
func(){
//减值迭代优化循环
for
(
var
i=values.length-1; i>=0; i--){
...
}
}
循环优化大串联
如果我们把上面所有的循环优化方式集中在一块,写法会是这样子滴:
function
func(){
//循环优化大串联
var
i;
//优化变量声明
var
divs = document.getElementsByTagName(
"div"
);
for
(i=divs.length-1; i>=0; i-=1){
//优化循环中动态集合读取、减值迭代、用i-=1 代替 i--
...
}
}
老实说,上面这个循环优化大串联性能是提高了,但可读性也降低到了一个新的高度。你代码写的再风骚,也得让人有个接受的地步那,做为团队开发,上面这个串联似乎还是不是特别可取,个人还是提倡部分优化,以优化性能的前提下兼顾可读性:
function
func(){
//合理的循环优化
var
i,len;
//优化变量声明
var
divs = document.getElementsByTagName(
"div"
);
for
(i=0, len = divs.length; i<len; i++){
//优化循环中动态集合读取,必要时也可以用i+=1 代替 i++
...
}
}
个人比较倾向于上面的这段JS循环。合理优化循环提升了代码的性能,又兼顾了可读性,可谓是一箭双雕,万事大吉!
- 再谈javascript的for循环性能
- Javascript for 循环的坑
- javascript 里的for循环
- javaScript的for in 循环
- javascript的for in 循环
- for 循环性能比较 提高for循环的效率
- javascript中的for in循环和for循环的使用
- javascript中的for in循环和for循环的使用
- JavaScript中for循环和for in 循环的区别
- javascript中的for in循环和for循环的使用
- javascript中的for in循环和for循环的使用
- javascript中的for in循环和for循环的使用
- javascript中的for in循环和for循环的使用
- for 循环嵌套性能的比较
- java 中for循环的性能测试
- JS--for循环的性能优化
- 嵌套for循环语句的性能优化
- 优化JavaScript处理循环的性能
- 柱状图中找到最大的矩形
- Ubuntu文件系统
- Python爬虫抓取网页图片
- 开发板的串口的作用
- Tomcat - 解决which must be escaped when used within the value错误
- 再谈javascript的for循环性能
- Codeforces 430 A. Points and Segments (easy)
- jboss7应用服务器开发的网页让局域网其他机器也能访问
- JDBC中PreparedStatement接口提供的execute、executeQuery和executeUpdate之间的区别及用法
- C++和C中的struct区别
- OSI/RM网络7层体系
- linux下环境变量的设置
- 在ubuntu10.4服务器版本下安装vsftp----续
- struts2+spring4+hibernate4整合时 org.hibernate.service.jta.platform.spi.JtaPlatform 异常