如何遍历数组的元素?20年前,当JavaScript出现时,你可能会这样做:
for (var索引=0;索引myArray.lengthindex){ console . log(my array[index]);} for (var索引=0;索引myArray.lengthindex){ console . log(my array[index]);}从ES5开始,您可以使用内置的forEach方法:
JavaScriptmyArray.forEach(函数(值){ console.log(值);});myArray.forEach(函数(值){ console.log(值);});代码比较简单,但是有一个小缺点:不能使用break语句跳出循环,也不能使用return语句从闭包函数返回。
使用-的语法遍历数组会方便得多。
那么,用for-in怎么样?
for(my array中的var索引){//不要在实际的代码控制台中这样做. log(my array[index]);} for(my array中的var index){//不要在实际的代码控制台. log(my array[index]);}这不好,因为:
上述代码中的索引变量将是诸如“0”、“1”、“3”等字符串。而不是数字类型。如果使用字符串的索引参与某些操作(' 2' 1=='21 '),结果可能不符合预期。不仅会遍历数组本身的元素,还会遍历用户添加的expando元素。例如,如果一个数组有这样一个属性myArray.name,那么在一定的周期内就会出现index='name '的情况。此外,甚至可以遍历数组原型链上的属性。最不可思议的是,在某些情况下,上面的代码会以任何顺序遍历数组元素。
简单地说,for-in被设计为遍历包含键值对的对象,这对于数组来说并不友好。强大的for-of循环
记得上次提到ES6不会影响现有JS代码的正常运行。成千上万的网络应用程序依赖于for-in的特性,甚至是数组。因此,从来没有人提出“改进”现有的for-in语法来解决上述问题。ES6解决这个问题的唯一方法是引入一种新的循环遍历语法。
这是新语法:
for(my array的var值){ console.log(值);} for(my array的var值){ console.log(值);}通过引入上面的for-in语法,它看起来并不那么令人印象深刻。稍后,我们将介绍森林的奇迹。现在你只需要知道:
这是遍历数组最简单、最直接的方法,避免了for-in语法中的所有坑。与forEach()不同,它支持break、continue和return语句。forin用于遍历对象的属性。
For-of用于遍历数据,就像数组中的元素一样。
然而,这并不是for-of的全部功能,下面还有更多令人兴奋的部分。支持-of的其他集合
For-of不仅是为数组设计的,也可以用于类数组的对象,比如DOM对象的集合NodeList。
它还可以用来遍历字符串,字符串被视为Unicode字符的集合:
它也适用于“映射”和“设置”对象。
可能你没听说过Map和Set对象,因为它们是ES6中的新对象,后面会有单独的文章详细介绍。如果您在其他语言中使用过这两个对象,那就简单多了。
例如,可以使用Set对象复制数组元素:
JavaScript//用一组单词组成一个集合=新集合(单词);//从单词数组中创建一个集合=新集合(单词);当您获得一个Set对象时,您可能会遍历该对象,这非常简单:
for(uniqueWords的var word){ console . log(word);} for(uniqueWords的var word){ console . log(word);}Map对象由键值对组成,键值对的遍历方式略有不同。您需要使用两个独立变量分别接收键和值:
for(phone bookmap的var [key,value]){ console . log(key的电话号码为: ' value);} for(phone bookmap的var [key,value]){ console . log(key的电话号码为: ' value);}到目前为止,你已经知道JS已经支持了一些集合对象,以后还会支持更多。的for语法是为这些集合对象设计的。
For-of不能直接用于遍历对象的属性。如果要遍历对象的属性,可以使用for-in语句(这就是for-in的用途),或者使用以下方法:
//将对象自身的可枚举属性转储到console for(object . keys(someObject)的var键){ console . log(key ' : ' someObject[key]);} //将对象自己的可枚举属性转储到console for(object . keys(someObject)的var键){ console . log(key ' : ' someObject[key]);}内在原理
“好的艺术家抄袭,伟大的艺术家偷窃。”-帕布罗毕加索
ES6中增加的新特性不是随机的,它们中的大多数已经在其他语言中使用过,并且已经被证明非常有用。
For-of语句,在C、JAVA、C#和Python中都有类似的循环语句,用来遍历这种语言及其标准库中的各种数据结构。
像其他语言中的for和foreach语句一样,for-of需要遍历的对象来实现特定的方法。所有数组、映射和集合对象都有一个共同点,那就是它们都实现了一个迭代器方法。
然后,如果您愿意,您可以为任何其他对象实现迭代器方法。
就像你可以为一个对象实现一个myObject.toString()方法,告诉JS引擎如何将一个对象转换成字符串;还可以为任何对象实现myObject[Symbol.iterator]()方法,告诉JS引擎如何遍历对象。
例如,如果您正在使用jQuery,并且非常喜欢使用它的每一个()方法,并且现在您想要使所有jQuery对象都支持-of语句,那么您可以这样做:
//由于jQuery对象类似数组,//给它们相同的迭代器方法Arrays havejquery . prototype[symbol . iterator]=array . prototype[symbol . iterator];//由于jQuery对象类似数组,//给它们相同的迭代器方法Arrays havejquery . prototype[symbol . iterator]=array . prototype[symbol . iterator];你可能想知道为什么[Symbol.iterator]语法看起来如此奇怪。这句话到底是什么意思?问题的关键在于方法名,可以由es标准委员会命名为iterator()。但是,一个名为“迭代器”的方法可能已经存在于现有对象中,这将导致代码混乱,并违反最大兼容性原则。因此,标准委员会引入了符号,而不仅仅是字符串,作为方法名。
符号也是ES6的一个新特性,稍后将在单独的文章中介绍。现在你只需要知道标准委员会引入了全新的Symbol,比如Symbol.iterator,为了不与之前的代码冲突。唯一的缺点是语法有点奇怪,但这对于这个强大的新功能和完美的向后兼容性来说微不足道。
具有[Symbol.iterator]()方法的对象被认为是可迭代的。在下面的文章中,我们将看到“可遍历对象”的概念贯穿了整个语言,不仅在for-of语句中,而且在Map和Set的构造函数和析构函数中,以及在新的扩展运算符中。迭代器对象
通常我们不会从头开始完全实现迭代器对象。下一篇文章会告诉你为什么。但是为了完整起见,让我们看看迭代器对象是什么样子的。如果您跳过这一部分,您将会错过一些技术细节。)
就拿for-of语句来说,它首先调用遍历集合对象的[Symbol.iterator]()方法,该方法返回一个iterator对象,该对象可以是任何带有. next方法的对象;然后,在for-of的每个循环中。迭代器对象上的下一个方法将被调用。以下是最简单的迭代器对象之一:
var zeroesforeviriterator={[symbol . iterator]: function(){ return this;},next : function(){ return { done : false,value : 0 };}};var zeroesforeviriterator={[symbol . iterator]: function(){ return this;},next : function(){ return { done : false,value : 0 };}};在上面的代码中,每次。调用next()方法,将返回相同的结果,这将告诉for-of语句循环遍历尚未完成,并告诉for-of语句此循环的值为0。这意味着for(zero forever iterator的值){}是一个无限循环。当然,典型的迭代器并不那么简单。
ES6的迭代器通过两个属性来标识每个遍历结果:完成了。价值。这是迭代器的设计原则,不同于其他语言的迭代器。在Java中,迭代器对象应该使用。hasNext()和。next()方法。在Python中,迭代器对象只有一个。next()方法,当没有遍历元素时,将引发StopIteration异常。但从根本上讲,这三种设计都返回了相同的信息。
迭代器对象也可以选择性地实现方法。return()和。投掷。如果循环由于异常或使用break和return操作符而提前退出,迭代器的。方法,迭代器对象占用的资源可以通过实现。return()方法,但是大多数迭代器不需要实现这个方法。Throw(exc)是一个特例:这个方法在遍历过程中永远不会被调用。我将在下一篇文章中详细介绍这种方法。
既然我们知道了for-of的所有细节,我们可以简单地重写这个语句。
第一个是for-of循环:
for(var of repeatable){语句} for(var of repeatable){语句}这只是一个语义实现,使用了一些底层方法和几个临时变量:
var $ iterator=ITERABLE[symbol . iterator]();var $ result=$ iterator . next();while(!$ result . done){ VAR=$ result . value;语句$ result=$ iterator . next();} var $ iterator=ITERABLE[symbol . iterator]();var $ result=$ iterator . next();while(!$ result . done){ VAR=$ result . value;语句$ result=$ iterator . next();}上述代码不涉及如何调用。return()方法,所以我们可以添加相应的处理,但我认为这会影响我们对内部原理的理解。for-of语句使用起来非常简单,但是其中有很多细节。和睦相处
目前,火狐的所有版本都已经支持for-of语句。默认情况下,Chrome禁用此语句。可以在地址栏输入chrome ://标志进入设置页面,然后勾选“实验JavaScript”选项。微软的Spartan浏览器也支持这种说法,但IE不支持。如果你想在Web开发中使用这个语句,并且需要兼容IE和Safari浏览器,那么可以使用Babel或者谷歌的Traceur等编译器,将ES6代码转换成对Web友好的ES5代码。
在服务器端,我们不需要任何编译器——您可以直接在io.js中使用这个语句,或者在NodeJS启动时使用- harmony启动选项。
{done: true}