和我一起学习Javascript循环

和我一起学习Javascript循环
1。优先于数组而不是对象类型来表示一组序列。

ECMAscript标准不指定在Javascript的对象类型的属性顺序存储。

但当使用..在循环来遍历属性的对象,它真的需要依赖于一定的秩序。因为ECMAscript并未明确规定这一序列,每个Javascript执行引擎可以实现按照自己的特点,所以在不同的执行环境,行为的一致性,在循环中可以..不能保证。

例如,调用报表方法时下列代码的结果是不确定的:
功能报告排行榜){
var结果;
var I=1;
为(最高记录变量名){ / /不可预知的顺序
结果+++名称++
{姓名}高分+ ;
++;
}
返回结果;
}
报表(名称:点:{,{ 1110100 },
{名称:史提夫
{名称:比利点:1050200 });

如果您确实需要确保操作结果基于数据顺序,最好使用数组类型来表示数据,而不是直接使用对象类型。同时,尽量避免使用for for循环,并使用显式for循环:
功能报告(排行榜){
var结果;
对于(var i = 0,n = highscores.length;i < n;i++){
VaR得分=高分{我};
结果=(i + 1)+ +。
score.name +:+ score.points + ;
}
返回结果;
}
报表(名称:点:{,{ 1110100 },
{名称:史提夫
{名称:比利点:1050200 });
1。Hank:11101002。史提夫:10645003。比利:1050200
另一个特别依赖的行为是浮点数的计算。
var评级= {
OD将狩猎:0.8,
神秘河:0.7,
21:0.6,
怀疑:0.9
};
在第2项中,浮点数的增加甚至不能满足交换律。

(0.1 + 0.2)+ 0.3的结果和0.1 +(0.2 + 0.3)的结果分别为

0.600000000000001和0.6

因此,浮点数的算术运算不能以任何顺序使用。
var = 0,计数= 0;
对于(var中的var键)不可预知的顺序
总=评级{键};
计数+;
}
总数计数;
合计;
当..在遍历顺序不同时,最终总的结果是不同的,下面是两个计算序列及其相应的结果。
(0.8 + 0.7 + 0.6 + 0.9 4 0.75)
(0.6 + 0.8 + 0.7 + 0.9 4 0.7499999999999999)
当然,对于浮点数计算问题,有一种用整数表示的方法。例如,我们首先将浮点数10倍以上放大到整数数据,然后计算后减少10倍。
(8 + 7 + 6 + 9) 4 10 0.75
(6 + 8 + 7 + 9) 4 10 0.75
2。不添加枚举(枚举)属性object.prototype

如果你的代码依赖于..在循环来遍历属性的对象的类型,不添加任何枚举属性的object.prototype。

然而,当加强Javascript的执行环境,你经常需要向object.prototype对象添加新的属性或方法。例如,你可以添加一个方法在一个对象的所有属性名称:
object.prototype.allkeys =函数(){
var结果{ };
对于(在此中的var键){
result.push(关键);
}
返回结果;
};
但结果如下:
({:1,B 2,C 3 })(。allkeys); / / {allkeys
一个可行的解决方案是使用一个函数而不是定义对Object.prototype的一种新方法:
功能allkeys(obj){
var结果{ };
对于(OBJ VAR键){
result.push(关键);
}
返回结果;
}
但如果你真的需要添加新的属性到Object.prototype,不想这个属性被遍历的..在环,你可以利用ES5环境提供object.defineproject方法。
object.defineproperty(object.prototype,allkeys
值:函数(){
var结果{ };
对于(在此中的var键){
result.push(关键);
}
返回结果;
},
可写的:真的,
枚举:假,
配置:真
});
上述代码的关键部分是设置可枚举属性设置为false。这样,这个属性不可穿越的..在环。

三.对于数组遍历,for循环是首选,而不是for循环

尽管上一个项目已经说明了这个问题,但您能看到下面代码部分的最终平均值是多少吗
var分数= { 98, 74, 85,77, 93, 100,89 };
var总= 0;
对于(分数中的var得分){
总分;
}
VAR平均总 / scores.length;
平均值;
通过计算,最终结果应该是88。

但是不要忘了在for for循环中,遍历始终是键,而不是值,数组也是一样的,所以for循环中的分数不是期望的98, 74,而是一系列的值,而是一系列的索引,比如0, 1,等等。

所以你可能认为最后的结果是:

(0 + 1 +…+ 6) / 7 = 21

但答案是错误的,另一个关键点是键的类型在for循环中总是字符串类型,所以+操作符的操作实际上是字符串拼接操作。

最后的总数实际上是一个字符串00123456。转换为数值类型的字符串的值为123456,然后除以元素数的7,最终结果是:17636.571428571428。

因此,最好是数组遍历,或者for循环的标准。

4。优先遍历遍历方法,而不是循环。

使用循环时,很容易侵犯干(不要重复自己)的原则。这是因为我们通常选择复制粘贴的方法来避免写一段循环语句。但这样的代码中有很多重复的代码,和开发商都没有意义重复的轮子。更重要的是,它是容易被忽视的循环时,复制和粘贴的细节,如起始索引值,终止判断条件,等等。

例如,下面的for循环有这个问题,假设n是set对象的长度:
对于(var i = 0;i <;n;+ +){ }
终止条件错误应为i < n
对于(var i = 1;i <;n;+ +){ }
启动变量错误应该是i = 0
对于(var i = n;i = 0;i…){ }
初始变量应该是错误,i = n - 1
对于(var i = n 1;i 0;i…){ }…
终止条件错误应为i=0
这是很容易在一些循环的细节犯错,利用Javascript闭包(参见条款11),循环的细节可以封装重用。事实上,ES5提供了许多方法来处理这个问题,array.prototype.foreach是最简单的一种,我们可以把这样的循环:
循环使用
对于(var i = 0,n = players.length;i < n;i++){
球员{我}得分+ +;
}

/ /每
players.foreach(功能(P){)
p.score + +;
});

除了遍历集合对象之外,另一种常见的模式是对原始集合中的每个元素进行一些操作,然后得到一个新集合。我们还可以使用foreach方法实现如下:
循环使用
var裁剪{ };
对于(var i = 0,n = input.length;i < n;i++){
Trimmed.push(输入{我}。修剪());
}

/ /每
var裁剪{ };
input.foreach(函数(s){)
Trimmed.push(s.trim());
});

但由于这种方式是将一套一套的常见方式,ES5还提供array.prototype.map方法使代码更简单和优雅。
VaR修剪= input.map(function(){)
返回s.trim();
});
此外,有一个共同的模式,过滤收集在一定的条件下,得到原set.array.prototype.filter子集提供ES5实施这一模式。该方法以谓语为参数,它是一个函数返回TRUE或FALSE:返回true意味着元素将被保留在新的集合;返回false意味着元素不会出现在新的集合。例如,我们使用下面的代码过滤物品的价格,只有把价格在{ min,max }范围:
listings.filter(功能(上市){)
返回listing.price min listing.price <= > =最大;
});
当然,以上方法在一个环境支持ES5可用。在其他环境中,我们有两个选择:1、使用第三方库,如下划线或lodash,他们都相当一般的方式来操纵对象和集合提供。2。根据自己定义的需要。

例如,下面的方法被定义为根据一定的条件获取集合中的一些元素:
功能takeWhile(A,PRED){
var结果{ };
对于(var i = 0,n = a.length;i < n;i++){
如果(!PRED(一个{我},我)){
打破;
}
结果{ { } };
}
返回结果;
}

var前缀= takeWhile({ 1, 2, 4,8, 16, 32 },{功能(N))
返回n<10;
});{ 1, 2, 4,8 }

为了更好的利用这种方法,我们可以定义它的array.prototype对象,和具体的影响可以被称为项目42。
array.prototype.takewhile =功能(PRED){
var结果{ };
对于(var i = 0,n = this.length;i < n;i++){
如果(!PRED(这{我},我)){
打破;
}
结果{这个{ { } };
}
返回结果;
};

var前缀= { 1, 2, 4,8, 16, 32 }。takeWhile(功能(N){)
返回n<10;
});{ 1, 2, 4,8 }

这是更好地使用一个循环只有一次比使用遍历功能:当你需要使用break和continue。例如,当使用foreach执行上述takeWhile方法,会有一个问题,你怎么做当你不满足谓词
功能takeWhile(A,PRED){
var结果{ };
a.foreach(函数(X,I){
如果(!PRED(x)){

}
结果{;
});
返回结果;
}
我们可以使用内部异常来判断,但也有点笨拙和低效:
功能takeWhile(A,PRED){
var结果{ };
无功earlyexit = {}; / /独特的价值信号回路
{试
a.foreach(函数(X,I){
如果(!PRED(x)){
把earlyexit;
}
结果{;
});
} catch(e){
如果(e)!= earlyexit){ / /只抓earlyexit
把E;
}
}
返回结果;
}
但在使用foreach,代码是更详细的比之前使用它。这显然是一个问题。对于这个问题,提供了一些方法和ES5每处理一个提前终止循环,其用法如下:
{ 1, 10, 100 }。一些(函数(x){返回} > 5;;)
{ 1, 10, 100 }。一些(函数(x){返回x 0);

{ 1, 2, 3,4, 5 }。每个(函数(x){返回} > 0;;)
{ 1, 2, 3,4, 5 }。每个(函数(x){返回x < 3);false / false);
这两种方法都是短路法(短路):如果某个方法谓词中有一个元素是真的,那么一些将返回;每个方法中只有一个元素返回假谓词,然后每一个方法都返回false。

作为一个结果,takeWhile可以实现如下:
功能takeWhile(A,PRED){
var结果{ };
每个(函数,x,i){
如果(!PRED(x)){
返回false
}
结果{;
返回true
});
返回结果;
}
事实上,这是函数式编程的思想。在函数式编程中,很少看到显式for循环或while循环。循环的细节被很好地封装起来。

5。总结

在for循环中不依赖于遍历的顺序。
当使用对象类型保存数据时,必须确保数据中的数据是无序的。
当需要用顺序表示一个集合时,使用数组类型而不是对象类型。
避免加入任何性质的Object.prototype。
如果这是真的,有必要对Object.prototype添加方法的特性,你可以考虑使用一个独立的功能。
使用object.defineproperty添加不能被..在环的性质。
遍历数组时,使用for循环的标准,而不是使用for循环。
为了提高性能,有必要预先考虑阵列的长度。
用遍历的方法array.prototype.foreach和array.prototype.map代替循环,使代码更清晰易读。
对于重复的循环,您可以考虑通过第三方提供的方法或由它们自己实现的方法来提取它们。
在某些场合,显式循环仍然可用,因此可以使用某些或每种方法。
以上就是本文的全部内容,希望通过这篇文章,我们能对Javascript循环的原理有更多的了解,并共同进步。
免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部