资讯专栏INFORMATION COLUMN

[译]JavaScript ES6迭代器指南

daryl / 2159人阅读

摘要:前言又称提供一个全新的迭代器的概念,它允许我们在语言层面上定义一个有限或无限的序列。后者可以被用来帮助我们理解迭代器。但是当我们使用迭代器时,这个问题就迎刃而解了。是中的新语法,用来配合迭代器。这是因为数组的迭代器只返回其中预期的元素。

前言

EcmaScript 2015 (又称ES6)提供一个全新的迭代器的概念,它允许我们在语言层面上定义一个(有限或无限的)序列。

暂时先抛开它。我们对于for循环以及它的兄弟for-in循环,都已经十分的熟悉。后者可以被用来帮助我们理解迭代器。

jsfor (var key in table) {
  console.log(key + " = " + table[key]);
}

对于for-in循环,它有许多的问题。但是最大的问题,便是它不保证迭代的顺序。但是当我们使用ES6迭代器时,这个问题就迎刃而解了。

for-of

for-of是ES6中的新语法,用来配合迭代器。

jsfor (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 () {} }的对象。

jstable[Symbol.iterator] = function () {
   return {
    next: function () {}
  }
}

然后,在for-of循环每次调用next()函数时,它需要返回一个类似于{value: …, done: [true/false]}的对象。所以,一个迭代器的完整实现类似于如下的例子:

jstable[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()函数永远不被调用的话,我们就浪费了性能。所以让我们来优化它:

jstable[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-offor-in的差别

理解for-offor-in之间的差别,是十分重要的。以下是一个简单的,但是非常好的解释差别的例子:

jsvar 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循环仅打印出了数组中的值,忽略了其他属性。这是因为数组的迭代器只返回其中预期的元素。

内置迭代器

StringArrayTypedArrayMapSet都是内置迭代器,因为它们的原型中都有一个Symbol.iterator方法。

jsvar string = "hello";

for (var chr of string) {
  console.log(chr); // h, e, l, l, o
}
解构赋值

解构操作同样也接受一个迭代器:

jsvar hello = "world";
var [first, second, ...rest] = [...hello];
console.log(first, second, rest); // w o ["r","l","d"]
无限迭代器

只要永远不返回done: true,就实现了一个无限迭代器。当然,需要极力避免出现这种情况。

jsvar 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函数

如果你还不了解ES6 generator 函数,请参考MDN文档。简而言之,generator函数是当前被谈论最多的ES6特性,它是一个可以暂时退出,并且稍后重新进入继续执行的函数。在多次的进入中,它的上下文(绑定的变量)是会被保存的。generator函数自身就是一个迭代器,来看下面的例子:

jsfunction* 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函数重写我们上面的迭代器:

jstable[Symbol.iterator] = function* () {
  var keys = Object.keys(this).sort();

  for (var item of keys) {
    yield item;
  }
}
最后

迭代器给JavaScript中的循环,generator函数和值序列(value series)带来了一个新的维度。你可以使用它,定义一个类中,它的值的排序方式,也可以用通过其来创建一个惰性的或无限的序列,等等。

原文地址

https://strongloop.com/strongblog/introduction-to-es6-iterators/

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85832.html

相关文章

  • 】前端练级攻略

    摘要:由于系统变得越来越复杂,人们提出了称为预处理器和后处理器的工具来管理复杂性。后处理器在由预处理器手写或编译后对应用更改。我之前建议的文章,,也涵盖了预处理器相关的知识。 译者:前端小智 原文:medium.freecodecamp.org/from-zero-t… medium.freecodecamp.org/from-zero-t… 我记得我刚开始学习前端开发的时候。我看到了很多文章及...

    wuyumin 评论0 收藏0
  • 2017-08-20 前端日报

    摘要:前端日报精选数组所有全解密原生实现最简单的图片懒加载译如何抓取数据中种常见的内存泄露陷阱内部原理,第一部分基础渲染前端国际化中文深入理解笔记模块掘金译热的冷的掘金模块,桌面端的支付请求,和迷津欲有问遮罩层状态丢失及解决方案全 2017-08-20 前端日报 精选 JavaScript数组所有API全解密原生JS实现最简单的图片懒加载【译】React如何抓取数据JavaScript 中 ...

    molyzzx 评论0 收藏0
  • [] 从 CoffeeScript 迁移到 ES6

    摘要:语法校验会给出警告当你仍在使用或不通过任何关键字声明变量时。但是如果脚本中还有其他的普通导出,就会得到非常奇怪的结果这个坑爹的情况目前还没有任何好的解决方案。 我在多年前爱上了coffeScript。对于javaScript,我一直保持着深沉的爱,也十分高兴得看到node.js的快速发展,但是作为一个有python背景的程序员,我更喜欢coffeeScript的简练语法。 在任何一个活...

    刘东 评论0 收藏0
  • 性能优化

    摘要:如果你的运行缓慢,你可以考虑是否能优化请求,减少对的操作,尽量少的操,或者牺牲其它的来换取性能。在认识描述这些核心元素的过程中,我们也会分享一些当我们构建的时候遵守的一些经验规则,一个应用应该保持健壮和高性能来维持竞争力。 一个开源的前端错误收集工具 frontend-tracker,你值得收藏~ 蒲公英团队最近开发了一款前端错误收集工具,名叫 frontend-tracker ,这款...

    liangzai_cool 评论0 收藏0
  • ES6迭代的简单指南和示例

    摘要:我们将从概念上理解迭代器是什么,以及在何处使用它们和示例。同时返回一个名为迭代器的对象,这个迭代器将拥有一个名为的方法,该方法将返回一个具有键值为和的对象。下图可以帮助建立可迭代对象迭代器和之间的关系,这种关系称为迭代协议。 showImg(https://segmentfault.com/img/bVbkk18?w=1000&h=562); 我们将在本文中分析迭代器。迭代器是在Jav...

    Betta 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<