JS迭代器之for-in(of)
2017-12-28 15:31
549 查看
EcmaScript 2015 (又称ES6)提供一个全新的
输出: 0 = 2 1 = 4 2 = 6 3 = 8对于
迭代器的概念,它允许我们在语言层面上定义一个(有限或无限的)序列。暂时先抛开它。我们对于
for循环以及它的兄弟
for-in循环,都已经十分的熟悉。后者可以被用来帮助我们理解迭代器。
1234 | var table = [2,4,6,8]; for ( var key in table) { console.log(key + ' = ' + table[key]); } |
for-in循环,它有许多的问题。但是最大的问题,便是它不保证迭代的顺序。但是当我们使用ES6迭代器时,这个问题就迎刃而解了。
for-of
for-of是ES6中的新语法,用来配合迭代器。
for (var key of table) { console.log(key + ' = ' + table[key]); }使用
for-of,我们得到的是一个可以保证顺序的迭代。为了让一个对象可以被迭代器所迭代,对象需要实现一个“迭代协议”,即拥有一个
Symbol.iterator属性。这个属性会被
for-of所使用,在我们的例子中,它就是
table[Symbol.iterator]。
Symbol.iterator也是在ES6中新增的内容,我们会在另一篇文章中详细讨论。在这里,我们只需认为它是对象的一个特殊属性,并且永远不会和其他普通属性产生冲突。
table[Symbol.iterator]的值,必须是一个符合“迭代协议”的函数,即它需要返回一个类似于
{ next: function () {} }的对象。
table[Symbol.iterator] = function () { return { next: function () {} } }然后,在
for-of循环每次调用
next()函数时,它需要返回一个类似于
{value: …, done: [true/false]}的对象。所以,一个迭代器的完整实现类似于如下的例子:
table[Symbol.iterator] = function () { var keys = Object.keys(this).sort(); var index = 0; return { next: function () { return { value: keys[index], done: index++ >= keys.length }; } } }
惰性执行
迭代器允许我们在第一次调用next()函数之后,再执行相应的逻辑。在上面的例子里,当我们调用迭代器的瞬间,我们就立刻执行了排序和取值的工作。但是,如果
next()函数永远不被调用的话,我们就浪费了性能。所以让我们来优化它:
table[Symbol.iterator] = function () { var _this = this; var keys = null; var index = 0; return { next: function () { if (keys === null) { keys = Object.keys(_this).sort(); } return { value: keys[index], done: index++ >= keys.length }; } } }完成代码:
var
table = [2,4,6,8];
//注意这个“迭代协议”必需放在table数组之后,开始迭代之前,不然能达到预期效果
table[Symbol.iterator] =
function
() {
var
_this =
this
;
var
keys =
null
;
var
index = 0;
return
{
next:
function
() {
if
(keys ===
null
) {
keys = Object.keys(_this).sort();
}
return
{
value: keys[index], done: index++ >= keys.length
};
}
}
}
for
(
var
key of table) {
console.log(key +
' = '
+ table[key]);
}输出: 0 = 2 1 = 4 2 = 6 3 = 8
for-of和
for-in的差别理解
for-of和
for-in之间的差别,是十分重要的。以下是一个简单的,但是非常好的解释差别的例子:
var list = [3, 5, 7]; list.foo = 'bar'; for (var key in list) { console.log(key); // 0, 1, 2, foo } for (var value of list) { console.log(value); // 3, 5, 7 }正如所见的,
for-of循环仅打印出了数组中的值,忽略了其他属性。这是因为数组的迭代器只返回其中预期的元素。
内置迭代器
String,
Array,
TypedArray,
Map和
Set都是内置迭代器,因为它们的原型中都有一个
Symbol.iterator方法。
var string = "hello"; for (var chr of string) { console.log(chr); // h, e, l, l, o }
解构赋值
解构操作同样也接受一个迭代器:var hello = 'world'; var [first, second, ...rest] = [...hello]; console.log(first, second, rest); // w o ["r","l","d"]
其中...rest是剩余参数(点击查看)。
无限迭代器
只要永远不返回done: true,就实现了一个无限迭代器。当然,需要极力避免出现这种情况。
var ids = { *[Symbol.iterator]: function () { var index = 0; return { next: function () { return { value: 'id-' + index++, done: false }; } }; } }; var counter = 0; for (var value of ids) { console.log(value); if (counter++ > 1000) { // let's make sure we get out! break; } }
Generator函数
如果你还不了解ES6generator函数,请参考MDN文档。简而言之,
generator函数是当前被谈论最多的ES6特性,它是一个可以暂时退出,并且稍后重新进入继续执行的函数。在多次的进入中,它的上下文(绑定的变量)是会被保存的。
generator函数自身就是一个迭代器,来看下面的例子:
function* list(value) { for (var item of value) { yield item; } } for (var value of list([1, 2, 3])) { console.log(value); } var iterator = list([1, 2, 3]); console.log(typeof iterator.next); // function console.log(typeof iterator[Symbol.iterator]); // function console.log(iterator.next().value); // 1 for (var value of iterator) { console.log(value); // 2, 3 }所以,我们可以使用
generator函数重写我们上面的迭代器:
table[Symbol.iterator] = function* () { var keys = Object.keys(this).sort(); for (var item of keys) { yield item; } }
最后
迭代器给JavaScript中的循环,
generator函数和值序列(value series)带来了一个新的维度。你可以使用它,定义一个类中,它的值的排序方式,也可以用通过其来创建一个惰性的或无限的序列,等等。THIS END点击打开原文
相关文章推荐
- JS:Trim() in javascript, how to define a function of checkinput for a WebControl(ascx)
- [Javascript] A function works like 'print_r()' in PHP to print out the details of an object for JS debugging
- JS中的 map, filter, some, every, forEach, for...in, for...of 用法总结
- js - for,(for...in...),forEach(...),(for...of..)差异与原理浅析
- JS里的for…in和for…of的用法
- js中的循环遍历数组中的元素,ES6(for-of)、ES5(forEach、for-in)、通用(for(i=0;i<length;i++))
- [js高手之路] es6系列教程 - 迭代器,生成器,for...of,entries,values,keys等详解
- js的for..in语句的用法详解
- phpcms抛出的二维数组转移到js,js中for....in遍历数组,用“.”连接来读出一维数组值
- Local Caching of Remote Images in AIR for Android
- js 之for..in、表单及事件触发
- 3D Fe3O4@Au@Ag nanoflowers assembled magnetoplasmonic chains for in situ SERS monitoring of plasmon-
- 详谈js中标准for循环与foreach(for in)的区别
- No mapping found for HTTP request with URI [/operation-platform/js/displaytag.js] in DispatcherServl
- Check for the content of input in UI
- 【JS】There’s Nostalgia in the Waters of Lake.js
- [Node.js] Take Screenshots of Multiple Dimensions for Responsive Sites using Nightmare
- JS:for...in...,Objects.keys()和Object.getOwnPropertyNames的区别
- Search for a string in an infinite stream of input string.
- 论文笔记:Chaotic Invariants of Lagrangian Particle Trajectories for Anomaly Detection in Crowded Scenes