uTools-Manuals/docs/javascript/Guide/Iterators_and_Generators.html
2019-04-21 11:50:48 +08:00

129 lines
15 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<article id="wikiArticle">
<div> <div class="prevnext" style="text-align: right;">
<p><a href="Guide/Details_of_the_Object_Model" style="float: left;">« 上一页</a><a href="Guide/Meta_programming">下一页 »</a></p>
</div></div>
<p class="summary">处理集合中的每个项是很常见的操作。JavaScript 提供了许多迭代集合的方法,从简单的<a href="Reference/Statements/for" title="for 语句用于创建一个循环,它包含了三个可选的表达式,三个可选的表达式包围在圆括号中并由分号分隔, 后跟一个在循环中执行的语句(通常是一个块语句)。"><code>for</code></a>循环到<a href="Reference/Global_Objects/Array/map" title="map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。"><code>map()</code></a><font face="Open Sans, Arial, sans-serif"><span style="font-weight: normal;"></span></font><a href="Reference/Global_Objects/Array/filter" title="filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。"><code>filter()</code></a>。迭代器和生成器将迭代的概念直接带入核心语言,并提供了一种机制来自定义<a href="Reference/Statements/for...of" title="for...of语句在可迭代对象包括 ArrayMapSetStringTypedArrayarguments 对象等等上创建一个迭代循环调用自定义迭代钩子并为每个不同属性的值执行语句"><code>for...of</code></a>循环的行为 。</p>
<p>更多详情,请参见:</p>
<ul>
<li><a href="Reference/Iteration_protocols">迭代协议</a></li>
<li><a href="Reference/Statements/for...of" title="for...of语句在可迭代对象包括 ArrayMapSetStringTypedArrayarguments 对象等等上创建一个迭代循环调用自定义迭代钩子并为每个不同属性的值执行语句"><code>for...of</code></a></li>
<li><a href="Reference/Statements/function*" title="function* 这种声明方式(function关键字后跟一个星号会定义一个生成器函数 (generator function),它返回一个  Generator  对象。"><code>function*</code></a><a href="Reference/Global_Objects/Generator" title="生成器对象是由一个 generator function 返回的,并且它符合可迭代协议和迭代器协议。"><code>Generator</code></a></li>
<li><a href="Reference/Operators/yield" title="yield 关键字用来暂停和恢复一个生成器函数((function* 或遗留的生成器函数)。"><code>yield</code></a><a href="Reference/Operators/yield*" title="yield* 表达式用于委托给另一个generator 或可迭代对象。"><code>yield*</code></a></li>
</ul>
<h2 id="迭代器">迭代器</h2>
<p>一个迭代器对象 ,知道如何每次访问集合中的一项, 并跟踪该序列中的当前位置。在  JavaScript 中 迭代器是一个对象,它提供了一个<code>next()</code> 方法,用来返回序列中的下一项。这个方法返回包含两个属性:<code>done</code><code>value</code></p>
<p>迭代器对象一旦被创建,就可以反复调用<code>next()</code></p>
<pre><code class="language-javascript"><code class="language-js"><span class="keyword token">function</span> <span class="function token">makeIterator</span><span class="punctuation token">(</span>array<span class="punctuation token">)</span><span class="punctuation token">{</span>
<span class="keyword token">var</span> nextIndex <span class="operator token">=</span> <span class="number token">0</span><span class="punctuation token">;</span>
<span class="keyword token">return</span> <span class="punctuation token">{</span>
next<span class="punctuation token">:</span> <span class="keyword token">function</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">{</span>
<span class="keyword token">return</span> nextIndex <span class="operator token">&lt;</span> array<span class="punctuation token">.</span>length <span class="operator token">?</span>
<span class="punctuation token">{</span>value<span class="punctuation token">:</span> array<span class="punctuation token">[</span>nextIndex<span class="operator token">++</span><span class="punctuation token">]</span><span class="punctuation token">,</span> done<span class="punctuation token">:</span> <span class="keyword token">false</span><span class="punctuation token">}</span> <span class="punctuation token">:</span>
<span class="punctuation token">{</span>done<span class="punctuation token">:</span> <span class="keyword token">true</span><span class="punctuation token">}</span><span class="punctuation token">;</span>
<span class="punctuation token">}</span>
<span class="punctuation token">};</span>
<span class="punctuation token">}</span></code></code></pre>
<p>一旦初始化,<code>next()</code>方法可以用来依次访问对象中的键值:</p>
<pre><code class="language-javascript"><code class="language-js"><span class="keyword token">var</span> it <span class="operator token">=</span> <span class="function token">makeIterator</span><span class="punctuation token">(</span><span class="punctuation token">[</span><span class="string token">'yo'</span><span class="punctuation token">,</span> <span class="string token">'ya'</span><span class="punctuation token">]</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
console<span class="punctuation token">.</span><span class="function token">log</span><span class="punctuation token">(</span>it<span class="punctuation token">.</span><span class="function token">next</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span>value<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="comment token">// 'yo'</span>
console<span class="punctuation token">.</span><span class="function token">log</span><span class="punctuation token">(</span>it<span class="punctuation token">.</span><span class="function token">next</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span>value<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="comment token">// 'ya'</span>
console<span class="punctuation token">.</span><span class="function token">log</span><span class="punctuation token">(</span>it<span class="punctuation token">.</span><span class="function token">next</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">.</span>done<span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="comment token">// true</span></code>
</code></pre>
<h2 id="生成器">生成器</h2>
<p>虽然自定义的迭代器是一个有用的工具,但由于需要显式地维护其内部状态,因此需要谨慎地创建。<strong><a href="Reference/Global_Objects/Generator" title="生成器对象是由一个 generator function 返回的,并且它符合可迭代协议和迭代器协议。">Generators</a></strong>提供了一个强大的选择:它允许你定义一个包含自有迭代算法的函数, 同时它可以自动维护自己的状态。</p>
<p>GeneratorFunction 是一个可以作为迭代器工厂的特殊函数。当它被执行时会返回一个新的Generator对象。 如果使用<a href="Reference/Statements/function*" title="function* 这种声明方式(function关键字后跟一个星号会定义一个生成器函数 (generator function),它返回一个  Generator  对象。"><code>function*</code></a>语法则函数将变为GeneratorFunction。</p>
<pre><code class="language-javascript">function* idMaker() {
var index = 0;
while(true)
yield index++;
}
var gen = idMaker();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
// ...
</code></pre>
<h2 id="可迭代对象">可迭代对象</h2>
<p>一个定义了迭代行为的对象,比如在<a href="Reference/Statements/for...of" title="for...of语句在可迭代对象包括 ArrayMapSetStringTypedArrayarguments 对象等等上创建一个迭代循环调用自定义迭代钩子并为每个不同属性的值执行语句"><code>for...of</code></a>中循环了哪些值。一些内置类型,如<a href="Reference/Array" title="REDIRECT Array"><code>Array</code></a><a href="Reference/Map" title="此页面仍未被本地化, 期待您的翻译!"><code>Map</code></a>具有默认的迭代行为,而其他类型(如<a href="Reference/Global_Objects/Object" title="Object 构造函数创建一个对象包装器。"><code>Object</code></a>)没有。</p>
<p>为了实现<strong>可迭代</strong>,一个对象必须实现 <strong>@@iterator </strong>方法,这意味着这个对象(或其<a href="Guide/Inheritance_and_the_prototype_chain">原型链</a>中的一个对象)必须具有带 <a href="Reference/Global_Objects/Symbol/iterator" title="Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。"><code>Symbol.iterator</code></a> 键的属性:</p>
<h3 id="自定义的可迭代对象">自定义的可迭代对象</h3>
<p>我们可以像这样实现自己的迭代:</p>
<pre><code class="language-javascript">var myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
for (let value of myIterable) {
console.log(value);
}
// 1
// 2
// 3
//or
console.log([...myIterable]); // [1, 2, 3]</code></pre>
<h3 id="内置可迭代对象">内置可迭代对象</h3>
<p><a href="Reference/String" title="此页面仍未被本地化, 期待您的翻译!"><code>String</code></a><a href="Reference/Array" title="REDIRECT Array"><code>Array</code></a><a href="Reference/Global_Objects/TypedArray" title="一个TypedArray 对象描述一个底层的二进制数据缓存区的一个类似数组(array-like)视图。事实上没有名为 TypedArray的全局对象也没有一个名为的 TypedArray构造函数。相反有许多不同的全局对象下面会列出这些针对特定元素类型的类型化数组的构造函数。在下面的页面中你会找到一些不管什么类型都公用的属性和方法。"><code>TypedArray</code></a><a href="Reference/Map" title="此页面仍未被本地化, 期待您的翻译!"><code>Map</code></a><a href="Reference/Global_Objects/Set" title="Set 对象允许你存储任何类型的唯一值无论是原始值或者是对象引用。"><code>Set</code></a> 都内置可迭代对象,因为它们的原型对象都有一个 <a href="Reference/Global_Objects/Symbol/iterator" title="Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。"><code>Symbol.iterator</code></a> 方法。</p>
<h3 id="用于可迭代对象的语法">用于可迭代对象的语法</h3>
<p>一些语句和表达式是预料会用于可迭代对象,例如 <a href="Reference/Statements/for...of" title="for...of语句在可迭代对象包括 ArrayMapSetStringTypedArrayarguments 对象等等上创建一个迭代循环调用自定义迭代钩子并为每个不同属性的值执行语句"><code>for-of</code></a> 循环,<a href="Reference/Operators/Spread_operator" title="REDIRECT Spread syntax">spread syntax</a><a href="Reference/Operators/yield*" title="yield* 表达式用于委托给另一个generator 或可迭代对象。"><code>yield*</code></a> 和<a href="Reference/Operators/Destructuring_assignment" title="解构赋值语法是一种 Javascript 表达式,它使得将值从数组,或属性从对象,提取到不同的变量中,成为可能。">destructuring assignment</a>.</p>
<pre><code class="language-javascript">for (let value of ['a', 'b', 'c']) {
console.log(value);
}
// "a"
// "b"
// "c"
[...'abc']; // ["a", "b", "c"]
function* gen() {
yield* ['a', 'b', 'c'];
}
gen().next(); // { value: "a", done: false }
[a, b, c] = new Set(['a', 'b', 'c']);
a; // "a"</code></pre>
<h2 id="高级生成器">高级生成器</h2>
<p>生成器根据需求计算它们的产出值,这使得它们能够有效地表示计算成本高的序列,或者甚至如上所述的无限序列。</p>
<p>The <a href="Reference/Global_Objects/Generator/next" title="next() 方法返回一个包含属性 done 和 value 的对象。该方法也可以通过接受一个参数用以向生成器传值。"><code>next()</code></a> 方法也接受可用于修改生成器内部状态的值。传递给<code>next()</code>的值将被视为暂停生成器的最后一个<code>yield</code>表达式的结果。</p>
<p>以下是使用 <code>next(x)</code> 重新启动 fibonacci 序列生成器:</p>
<pre><code class="language-javascript">function* fibonacci() {
var fn1 = 0;
var fn2 = 1;
while (true) {
var current = fn1;
fn1 = fn2;
fn2 = current + fn1;
var reset = yield current;
if (reset) {
fn1 = 0;
fn2 = 1;
}
}
}
var sequence = fibonacci();
console.log(sequence.next().value); // 0
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
console.log(sequence.next().value); // 3
console.log(sequence.next().value); // 5
console.log(sequence.next().value); // 8
console.log(sequence.next(true).value); // 0
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
</code></pre>
<p>你可以通过调用其<a href="Reference/Global_Objects/Generator/throw" title="throw() 方法用来向生成器抛出异常,并恢复生成器的执行,返回带有 done 及 value 两个属性的对象。"><code>throw()</code></a>方法强制生成器抛出异常,并传递应该抛出的异常值。这个异常将从当前挂起的生成器的上下文中抛出,就好像当前挂起的<code>yield</code>是一个<code>throwvalue</code>语句。</p>
<p>如果在抛出的异常处理期间没有遇到<code>yield</code>,则异常将通过调用 <code>throw()</code>向上传播,对 <code>next()</code>的后续调用将导致<code>done</code>属性为<code>true</code></p>
<p>生成器具有<a href="Reference/Global_Objects/Generator/return" title="return() 方法返回给定的值并结束生成器。"><code>return(value)</code></a> 方法,返回给定的值并完成生成器本身。</p>
<p></p><div class="prevnext" style="text-align: right;">
<p><a href="Guide/Details_of_the_Object_Model" style="float: left;">« 上一页</a><a href="Guide/Meta_programming">下一页 »</a></p>
</div><p></p>
</article>