我对新功能的讨论今天很兴奋,因为这个功能是6最惊人的特点。

这里的魔法意味着什么对于初学者来说,这个功能与以前的JS有很大的不同,甚至有点晦涩难懂。从某种意义上说,它完全改变了语言的共同行为,而这不是魔术。

不仅如此,这个特性还简化了程序代码,并将复杂的回调堆栈更改为直线的形式。

我铺路太多了吗以下是引言的开头部分,你可以判断自己。

简介

什么是发电机

请看下面的代码:


功能*妙语(name){
输出hello+ name +!;
我希望你喜欢博客文章;
如果(name.startswith(X)){
你的名字是怎样用x,+名字开始的,这很酷;
}
再见!;
}

功能*妙语(name){
输出hello+ name +!;
我希望你喜欢博客文章;
如果(name.startswith(X)){
你的名字是怎样用x,+名字开始的,这很酷;
}
再见!;
}




上面的代码是模仿猫的一部分(现在是一个非常流行的应用程序)。点击这里播放,如果你对代码感到困惑,让我们回到这里看看下面的解释。

它看起来像一个函数,称为生成器函数。它与我们的共同功能有许多相似之处,但我们可以看到以下两个差异。

通常函数以函数开始,但生成器函数以函数*开始。

在生成函数,产量是一个关键字,有点像回报。不同的是,所有的功能(包括发电机功能)只能返回一次,而函数发生器可以产生任何时间。产量表现暂停生成器函数执行后就可以恢复执行的地方暂停。

公共函数不能被中止,生成器函数可以,这是两者最大的区别。

原理

当妙语()叫什么




> VAR ITER =妙语(jorendorff );
{对象生成器}
> > iter.next()
{价值:你好jorendorff!!
> > iter.next()
{值:我希望你喜欢博客文章
> > iter.next()
{值:再见!
> > iter.next()
{值:未定义的,已完成的:真}


> VAR ITER =妙语(jorendorff );
{对象生成器}
> > iter.next()
{价值:你好jorendorff!!
> > iter.next()
{值:我希望你喜欢博客文章
> > iter.next()
{值:再见!
> > iter.next()
{值:未定义的,已完成的:真}




我们非常熟悉普通函数的行为。当函数被调用时,它将立即执行,直到函数返回或抛出异常,这是所有js程序员的第二天性。

调用函数发生器的方法和普通的函数:妙语连珠(jorendorff ),但调用生成器函数不立即执行,但返回生成器对象(以上ITER代码)立即暂停,然后函数的第一行代码的功能。

每次调用生成器对象的下一个()方法时,函数就开始执行,直到遇到下一个收益表达式为止。

这就是为什么我们每次打电话iter.next(),我们得到一个不同的字符串,这是函数内的产量表现产生。

当最后一iter.next()执行,达到发电机的功能,最终使了返回结果的属性值为true,和价值属性的值是未定义的。

现在,回到演示猫的演示中,尝试在代码中添加一些收益表达式,看看会发生什么。

从技术上讲,当发电机达到产量的表达功能执行时,堆栈帧,局部变量,函数参数,函数值从堆栈的临时位置是当前实施拆除,但发电机对象保持一个参考的栈帧,所以下一次你的电话。下一个()方法,可以恢复继续执行。

值得一提的是,生成器不是多线程的,在多线程语言中,可以同时执行多段代码,在执行资源的竞争下会产生不确定性和更好的性能,而生成器函数则不是这样。当生成器函数执行时,它与调用方在同一线程中执行。每个执行序列是确定的、有序的,执行序列不会改变。与线程不同,生成器函数可以挂在内部收益的标志点处。

通过引入生成器函数的执行、执行和恢复执行,我们知道生成器函数是什么。现在我们来问一个问题:生成器函数的用途是什么

迭代器

在文章的最后,我们知道迭代器不内置类6,但作为语言的一个扩展点,你可以通过执行{符号定义一个迭代器迭代器}()和下()。

然而,一个接口或需要编写一些代码,让我们看看如何在实践中实现一个迭代器,以实现范围迭代器为例,迭代器简单地从一个数字添加到另一个数字,有点像C语言中的(;)循环。




这应该是三次
为(取值范围(0, 3)){
Alert (Ding! 在地板# +价值);
}

这应该是三次
为(取值范围(0, 3)){
警惕(丁!在地板# +价值);
}



现在的一个解决方案是使用6类。(如果你不熟悉的语法课,没关系,我会在未来。介绍)




类rangeiterator {
构造函数(开始,停止){
this.value =开始;
this.stop =停止;
}

{迭代器}(){返回此};}

下一步(){
VaR值= this.value;
如果(值<此>停止){
这个值+ +;
返回{完成:false,值:};
{人}
返回{完成:true,值:未定义};
}
}
}

返回一个新的迭代器,计数 / from'start'to'stop。
函数范围(开始,停止){
返回新的rangeiterator(启动、停止);
}

类rangeiterator {
构造函数(开始,停止){
this.value =开始;
this.stop =停止;
}

{迭代器}(){返回此};}

下一步(){
VaR值= this.value;
如果(值<此>停止){
这个值+ +;
返回{完成:false,值:};
{人}
返回{完成:true,值:未定义};
}
}
}

返回一个新的迭代器,计数 / from'start'to'stop。
函数范围(开始,停止){
返回新的rangeiterator(启动、停止);
}




看看演示。

这种实现方式类似于java和快速执行。看起来很不错,但不能说上面的代码是完全正确的,代码没有任何错误,很难说,我们没有看到任何传统的循环代码:迭代器的协议迫使我们将循环分解。

在这一点上,您可能不太热衷于迭代器,它们很方便使用,但似乎很难实现。

我们可以引入一种新的实现方法来简化迭代器的实现。这里描述的生成器可以在这里使用吗让我们试试看。




函数*范围(开始,停止){
对于(var i =开始;i <停止;i + +)
屈服我;
}

函数*范围(开始,停止){
对于(var i =开始;i <停止;i + +)
屈服我;
}



看看演示。

代码的4行以上,完全可以取代以前的23行实施,更换整个rangeiterator类,这是由于发电机是天生的迭代器,以及所有的发电机实现。下一个()和(){ }符号。迭代器。你只需要在实现循环逻辑。

不使用发电机实现迭代器是被迫写长邮件,原本只是表达你的意思的话,那rangeiterator实现是漫长、令人困惑,因为它不使用循环语句的语法实现循环功能。利用发电机是我们需要掌握的方法。

我们可以用作生成器的迭代器的函数是什么

所以,任何对象都可以走过——写一台函数遍历,每遍历一个价值量,那么函数发生器的{符号执行。迭代器}的方法来遍历对象。

简化返回数组的功能——如果有一个函数在每次调用时返回一个数组,例如:


一维array'icons ' / /分
阵列的length'rowlength。进入
功能splitintorows(图标,rowlength){
var行= };
对于(var i = 0;i < icons.length;我= rowlength){
Rows.push(icons.slice(I,I + rowlength));
}
返回行;
}


一维array'icons ' / /分
阵列的length'rowlength。进入
功能splitintorows(图标,rowlength){
var行= };
对于(var i = 0;i < icons.length;我= rowlength){
Rows.push(icons.slice(I,I + rowlength));
}
返回行;
}




这种类型的函数可以用生成器简化:




功能* splitintorows(图标,rowlength){
对于(var i = 0;i < icons.length;我= rowlength){
产量icons.slice(I,I + rowlength);
}
}

功能* splitintorows(图标,rowlength){
对于(var i = 0;i < icons.length;我= rowlength){
产量icons.slice(I,I + rowlength);
}
}



它们之间的唯一区别是,前者在调用时计算所有结果并返回一个数组,后者返回一个迭代器,在需要时计算它,然后逐一返回。

无限大的结果集——我们不能建立一个无限大的数组,但是我们可以返回一个生成无限序列的生成器,每个调用方都可以从中获得任意数量的所需值。

重构复杂的循环——你想把复杂的函数和复杂的函数分解成两个简单的函数吗发电机在你重构工具箱的一个新的瑞士军刀,一个复杂的过程,我们可以重新生成数据集生成器函数部分,然后遍历它为:为(对mynewgenerator VaR数据(参数))。

6、一种工具来建立迭代器,不使用数据集过滤和地图提供了一个可扩展的库,但发电机可以用几行代码实现这些功能。

例如,假设你需要一种方法来实现相同的功能array.prototype.filter列表上。一块蛋糕:




功能*过滤器(测试、迭代){
为(可迭代的VAR项){
如果(测试(项目))
产量项目;
}
}


功能*过滤器(测试、迭代){
为(可迭代的VAR项){
如果(测试(项目))
产量项目;
}
}




Generator很实用,是吗当然,这是实现一个自定义迭代器最简单和直接的方式,并在6,迭代器是一个新的标准数据集和循环。

然而,这并不是发电机的全部功能。

异步代码

异步API通常需要回调函数,这意味着每次需要编写一个匿名函数来处理异步结果时,如果同时处理三个异步事务,我们会看到三个缩进级别的代码,而不仅仅是三行代码。

请看下面的代码:




}),('关闭',函数(){(){
完成(未定义的,未定义的);
}),(错误,函数(误差){ }
完成(错误);
});

}),('关闭',函数(){(){
完成(未定义的,未定义的);
}),(错误,函数(误差){ }
完成(错误);
});



异步API通常有错误处理的约定,不同的API有不同的约定。在大多数情况下,默认情况下会丢弃错误,有些甚至在默认情况下会被丢弃。

到目前为止,这些问题仍然是异步编程所必须付出的代价,我们已经接受了异步代码,但是我们不认为它像同步代码那样简单友好。

发电机给我们希望,我们可以停止使用上述方式。

Q.async()是将发电机和承诺过程异步代码的实验尝试,使我们的异步代码类似于相应的同步码。

例如:




制造噪音的代码。同步
功能制造噪音108.(){
摇动();
拨浪鼓();
辊();
}

制造噪音的代码。异步
返回一个已成为解析对象的允诺对象。
我们已经制造噪音了。
功能makenoise_async(){
返回Q.async(功能*(){()
产量shake_async();
产量rattle_async();
Yield roll_async ();
});
}

制造噪音的代码。同步
功能制造噪音108.(){
摇动();
拨浪鼓();
辊();
}

制造噪音的代码。异步
返回一个已成为解析对象的允诺对象。
我们已经制造噪音了。
功能makenoise_async(){
返回Q.async(功能*(){()
产量shake_async();
产量rattle_async();
产量roll_async();
});
}




最大的区别是,您需要在每个异步方法调用的前面添加收益关键字。

在Q.async,加入一个if语句或try catch异常处理就像是在同步代码的方式,减少了很多学习费用与其他方式相比,异步代码编写。

生成器为我们提供了一个更适合人脑思维的异步编程模型,但更好的语法可能更有用。在ES7,基于承诺和发电机的异步处理功能正在计划中,受到类似的功能在C #。

兼容性

在服务器端,你现在可以直接使用io.js发电机(或启动节点--和谐NodeJS)。

在浏览器端,只有Firefox 27和Chrome 39版本支持生成器。如果你想用它直接在网页上,你可以使用6巴别塔或眉目传情转换代码代码Web友好的ES5 ES6。

一些方法:js版的发电机是由Brendan Eich Python发电机首先实施,他指的是从图标的灵感落实实施,早在2006 2火狐吸收发电机。但规范化道路坎坷。一路上,它的语法和行为都发生了很大的变化。在Firefox和Chrome的6发电机是通过Andy Win。这项工作是由布隆伯格赞助的。

产量;

发电机还有一些零件没有被提及。我们还没有涉及到抛出()和返回()方法的使用,下一个()方法的可选参数,和生成*语法。

我们已经介绍了6非常重要的两个特点。现在我们可以大胆地说,6将改变我们的生活,看似简单的特点,但它是非常有用的。