JavaScript——for和for in 的性能比较与for循环的优化方案

在JavaScript中,我们遍历数组的时候经常需要用到for和for in。今天来比较一下这两个遍历方法的性能,并提供优化方案。

1.for 和for in的性能比较

我们都知道,for 和for in的时间复杂度一样,但是其性能有些许差距。具体有多大差距呢,下面我们来看一段代码。

<!DOCTYPE html>
<html>
<head>
		<meta http-equiv="Content-type" content="text/html";charset=utf-8>
		<script type="text/javascript" >
		"use strict";
		 /*如果不加"use strict";会报错:Uncaught SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode*/
			let arr = new Array();
		for(let i = 0, len = 1000000;i < len; i++){
			arr.push(i);
		}
 
		function for_add(my_arr){
			let sum = 0;
			for(let i = 0; i < my_arr.length; i++){
				sum += my_arr[i];//将数组中的数累加。
			}
		}
 
		function for_in_add(my_arr){
			let sum = 0;
			for(let key in my_arr){
				sum += my_arr[key];//将数组中的数累加。
			}
		}
 
		function timeTest(func,my_arr,str) {
			var start_time = null;
			var end_time = null;
			start_time = new Date().getTime();
			func(my_arr);
			end_time = new Date().getTime();
			console.log(str,(end_time - start_time).toString());//控制台输出时间差
		}
 
		timeTest(for_add,arr,'for_add');
		timeTest(for_in_add,arr,'for_in_add');



		</script>
</head>
<body>
</body>
</html>

这段代码定义了一个很大的数组,分别用for 和for in来遍历该数组,并在控制台输出这结束时间与开始时间差。运行结果如下:

由此我们可以看出,for的性能要比for in 的性能好很多,但这两种方法从字面上几乎一样,那到底是什么造成了这样的差距呢?

原因主要有以下几点: 

1.for...in的key是String类型,而非数字,它包含当前属性的名称或当前数组元素的索引,有转换过程,因此开销比较大;但是for循环的i是Number类型,开销较小。

2.for-in是用来迭代对象的属性或数组的每个元素,它需要穷举对象的所有属性,包括自定义的添加的属性也能遍历到,而for则是通过number遍历,因此开销较小。因此,for-in 大多时候用来遍历对象,而非遍历数组,遍历数组建议用for。

优化方案

1.for 循环的优化

(方法一)

当我们遍历数组时,下面的代码是我们常用的方法:

for(let i = 0; i < my_arr.length; i++){
				sum += my_arr[i];//将数组中的数累加。
			}

上面的代码看似没有什么问题,但是却包含了一个“超级拖延症患者”,即语句“i<my_arr.length”。这个语句的意思是:i<数组的长度。看起来好像没错,我们的确要数组长度作为判断条件,但这种写法,需要在每一次循环都计算一次数组长度,极大地增加了开销,想要达到同样的目的,有另一种更好的方法——将数组的长度先缓存起来。

(方法二)

var l=my_arr.length;
for(let i = 0; i < l; i++){
				sum += my_arr[i];//将数组中的数累加。
			}

将数组长度赋予一个变量,将该变量作为for循环中的判断条件,这样只需要计算一次数组长度,无需每次都计算,时间开销自然也就小了很多。

(方法三)

此外,如果不想要引入新的变量,我们可以用- -替代++

写法一:
var i ,arry=[]
    for(i=arry.length;i--;){
    //倒序对arry进行操作
}



写法二



var i,arry=[],i=arry.length;
while(i--){
    //对arry进行操作
}

(方法四)

除了这个方法,我们还可以运用JavaScript中的技巧,将判断与循环放在一起,一边循环一边赋值。如下:

for(let i = 0,l;l=my_arr[i++] ; ){
				sum += my_arr[i];//将数组中的数累加。
			}

上面的这种写法将变量直接放到for循环的条件语句中,获取当前的值再也不用在循环体里面定义变量存放,可以减少很多麻烦。但是这种写法,乍一看以为会报错,因为没有条件控制语句,不知道什么时候跳出循环。

但是假设数组长度为10,如果我们运行一下,会发现循环的次数也10。这是为什么呢? 这就和js的的语句规则有关了。

l=my_arr[i++]为true,而在JavaScript中,0,null,undefined,false和空字符串都会是false值。因此,在i变为0的时候自动转换为布尔值false,从而进行循环结束终止;如果arr[i++]大于了arr.length,则val就是未定义,判断为undefined,判断终止,循环结束。

因此,我们可以巧妙利用js中的特定技巧,利用0,null,undefined,false和空字符串进行判断,从而简写for循环。

总结:JS的for循环中,性能的优化主要通过减少循环体中变量的声明和外部方法的调用来实现。

猜你喜欢

转载自blog.csdn.net/Searchin_R/article/details/82927172