javascript 之迭代器
<h1>简介</h1><div class="lake-content">
<p id="u21b78091" class="ne-p"><span class="ne-text"> 迭代器是一种设计模式,可在容器对象 如 链表、数组上遍历,无需关心容器对象的内存分配的实现细节。简单的理解就是可以一个一个的依次拿到其中的数据,类似一个移动的指针,但是会告诉我们什么时候结束。这样我们可以拿到数据之后可以做一些我们需要做的事情。</span></p>
</div>
<h1> js 中的迭代器是什么样子的</h1>
<div class="lake-content">
<p id="u8d33aeca" class="ne-p"><span class="ne-text"> 在javascript 中迭代器是一个<strong>特殊对象</strong>,这个<span class="ne-text">迭代器对象有一个<strong>next()</strong>方法,每次调用都返回一个对象(结果对象)。结果对象有<strong>两个属性</strong>:一个是value,表示下一个将要返回的值;另一个是done,它是一个布尔类型的值,<span class="ne-text">如果已经迭代到序列中的最后一个值,则它为 <span class="ne-text">true<span class="ne-text">。迭代器还会保存一个内部指针,用来指向当前集合中值的位置,每调用一次next()方法,都会返回下一个可用的值,类似下面这个对象的结构。</span></span></span></span></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
next: </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> {
value:</span>''<span style="color: rgba(0, 0, 0, 1)">,
done: </span><span style="color: rgba(0, 0, 255, 1)">true</span> / <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
}
}
} </span></pre>
</div>
</div>
<h1>迭代协议</h1>
<p> 随着javascript 语言的能力进一步提升,新增了一些新的数据类型 如 Map、Set、WeakMap 等,为了这些不同的数据结构,可以统一的迭代,es6 增加了迭代协议这个东西。</p>
<p>迭代协议并不<span class="ne-text">是新的内置实现或语法,而是<strong><span class="ne-text">协议</span></strong><span class="ne-text">。这些协议可以被任何遵循某些约定的对象来实现。</span></span></p>
<div class="lake-content">
<p id="ue92f4649" class="ne-p"><span class="ne-text">迭代协议具体分为两个协议:<strong><span class="ne-text">可迭代协议和迭代器协议。</span></strong></span></p>
<p class="ne-p"><span class="ne-text" style="color: rgba(255, 0, 0, 1)"><strong><span class="ne-text">简单的理解就是在js 中任何对象只要满足迭代协议就可以遍历</span></strong></span></p>
</div>
<h2>可迭代协议</h2>
<div class="lake-content">
<p id="ufc7f1fbb" class="ne-p"><span class="ne-text">要成为<strong><span class="ne-text">可迭代</span></strong><span class="ne-text">对象, 一个对象必须实现 <span style="color: rgba(255, 0, 0, 1)"><strong><span class="ne-text">@@iterator</span></strong></span><span class="ne-text"> 方法。这意味着对象(或者它原型链<span class="ne-text">上的某个对象)必须有一个键为 <span class="ne-text">@@iterator<span class="ne-text"> 的属性,可通过常量 <span class="ne-text">Symbol.iterator</span><span class="ne-text"> 访问该属性:</span></span></span></span></span></span></span></p>
<p id="u12c02120" class="ne-p"><span class="ne-text">简单的理解,你想让一个东西可以遍历,那么这个东西要有一个 <span class="ne-text">@@iterator<span class="ne-text"> ,这个属性可以通过<strong><span class="ne-text">Symbol.iterator</span></strong><span class="ne-text"> 访问</span></span></span></span></p>
</div>
<div class="lake-content">
<table class="ne-table" style="height: 118px; width: 941px">
<tbody>
<tr>
<td width="375">
<p id="u5851bbf9" class="ne-p"><span class="ne-text">属性</span></p>
</td>
<td width="375">
<p id="ude87ed46" class="ne-p"><span class="ne-text">值</span></p>
</td>
</tr>
<tr>
<td width="375">
<p id="u97aa7fe2" class="ne-p"><span class="ne-text"></span></p>
</td>
<td width="375">
<p id="u5723ae70" class="ne-p"><span class="ne-text">一个无参数的函数,其返回值为一个符合迭代器协议<span class="ne-text">的对象。</span></span></p>
</td>
</tr>
</tbody>
</table>
<h2>迭代器协议</h2>
<div class="lake-content">
<p id="u68fd0d55" class="ne-p"><strong><span class="ne-text">迭代器协议</span></strong><span class="ne-text">定义了产生一系列值(无论是有限个还是无限个)的标准方式。当值为有限个时,所有的值都被迭代完毕后,则会返回一个默认返回值。</span></p>
<p id="ub2627121" class="ne-p"><span class="ne-text">只有实现了一个拥有以下语义(semantic)的 <strong><span class="ne-text">next()</span></strong><span class="ne-text"> 方法,一个对象才符合迭代器协议:</span></span></p>
<div class="lake-content">
<table id="lnbXf" class="ne-table" style="height: 216px; width: 956px">
<tbody>
<tr>
<td width="375">
<p id="u4d47c4b9" class="ne-p"><span class="ne-text">属性</span></p>
</td>
<td width="375">
<p id="u8784f203" class="ne-p"><span class="ne-text">值</span></p>
</td>
</tr>
<tr>
<td width="375">
<p id="uf1a30555" class="ne-p"><span class="ne-text">next</span></p>
</td>
<td width="375">
<p id="u732734c9" class="ne-p"><span class="ne-text">一个无参数函数,返回一个应当拥有以下两个属性的对象:</span></p>
<p id="udc9c1eff" class="ne-p"><strong><span class="ne-text">done</span></strong><strong><span class="ne-text">(boolean)</span></strong></p>
<p id="u13aaf0d0" class="ne-p"><span class="ne-text"><span style="color: rgba(255, 0, 0, 1)">next()</span><span class="ne-text"><span style="color: rgba(255, 0, 0, 1)"> 方法必须返回一个对象,该对象应当有两个属性:</span><span class="ne-text"> <span class="ne-text"><span style="color: rgba(255, 0, 0, 1)">done</span><span class="ne-text"> <span class="ne-text"><span style="color: rgba(255, 0, 0, 1)">和</span><span class="ne-text"> <span class="ne-text"><span style="color: rgba(255, 0, 0, 1)">value</span><span class="ne-text"><span style="color: rgba(255, 0, 0, 1)">,</span>如果返回了一个非对象值(比如<span class="ne-text"> <span class="ne-text">false<span class="ne-text"> <span class="ne-text">或<span class="ne-text"> <span class="ne-text">undefined<span class="ne-text">),则会抛出一个<span class="ne-text"><span class="ne-text"> </span><span class="ne-text"><span class="ne-text">异常(<span class="ne-text">"iterator.next() returned a non-object value"<span class="ne-text">)。</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
</td>
</tr>
</tbody>
</table>
</div>
<h2 class="ne-p"><span class="ne-text">迭代过程</span></h2>
<div class="lake-content">
<p id="ufabb94a0" class="ne-p"><span class="ne-text">当一个对象需要被迭代的时候(比如被写入一个 for...of<span class="ne-text"> 循环时),首先,会不带参数调用它的 <span class="ne-text">@@iterator<span class="ne-text"> 方法( <span style="color: rgba(255, 0, 0, 1)">此时返回的是结构是这样的</span><span class="ne-text"><span style="color: rgba(255, 0, 0, 1)"> { next: function () {}}</span>)<span class="ne-text">,然后使用此方法返回的<strong><span class="ne-text">迭代器</span></strong><span class="ne-text">获得要迭代的值(其实就是不断的调用这个next()方法)</span></span></span></span></span></span></span></p>
<h2 class="ne-p"><span class="ne-text"><span class="ne-text"><span class="ne-text"><span class="ne-text"><span class="ne-text"><span class="ne-text"><span class="ne-text">迭代总结</span></span></span></span></span></span></span></h2>
</div>
</div>
</div>
<div class="lake-content">
<p id="u0cff1f30" class="ne-p"><span class="ne-text">迭代协议可以总结为,一个东西要遍历,必须满足可迭代协议跟迭代器协议</span></p>
<ul class="ne-ul">
<li id="u5ed68b82"><span class="ne-text">可迭代协议:这个对象必须有@@iterator,可以通过<strong><span class="ne-text">Symbol.iterator</span></strong><span class="ne-text"> 访问</span></span></li>
</ul>
<ul class="ne-ul">
<li id="u3acb1386"><span class="ne-text">迭代器协议:是一个对象,这个对象的next() 函数返回一个对象,这个对象包括两个属性,一个是value,一个是done(boolean,是否是最后一个元素,done 为 true 时 value 可省略)</span></li>
</ul>
<p id="u32cb8b4b" class="ne-p"><span class="ne-text">也就是说 <span class="ne-text">迭代器对象本质上<span class="ne-text">,<span class="ne-text">就是一个指针对象。通过指针对象的<span class="ne-text">next()<span class="ne-text">,用来移动指针。</span></span></span></span></span></span></p>
<p class="ne-p"> </p>
<h1 class="ne-p">自定义迭代</h1>
<p>对象是没有实现迭代器,所以不能遍历对象,为了可以实现对象的遍历,我们需要在对象上实现上面说的迭代器,通常有两种写法,一种是传统的写法,这种需要自己去控制内部的状态,另外一种是利用生成器函数返回的<span style="color: rgba(255, 0, 0, 1)">Generator</span>的迭代器来实现,代码如下:</p>
<h2 class="ne-p">传统写法</h2>
<div class="cnblogs_code">
<pre>let obj =<span style="color: rgba(0, 0, 0, 1)"> {
name: </span>'joel'<span style="color: rgba(0, 0, 0, 1)">,
adress: </span>'gz'<span style="color: rgba(0, 0, 0, 1)">,
: () </span>=><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这里不要用this, 因为是return fn, this 会丢失</span>
let index = -1, atrrList =<span style="color: rgba(0, 0, 0, 1)"> Object.keys(obj);
const objIterator </span>=<span style="color: rgba(0, 0, 0, 1)"> {
next: () </span>=><span style="color: rgba(0, 0, 0, 1)"> {
let result </span>= ''<span style="color: rgba(0, 0, 0, 1)">
index</span>++
<span style="color: rgba(0, 0, 255, 1)">if</span> (index <<span style="color: rgba(0, 0, 0, 1)"> atrrList.length) {
result </span>=<span style="color: rgba(0, 0, 0, 1)"> {
value: atrrList,
done: </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
}
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
result </span>=<span style="color: rgba(0, 0, 0, 1)"> {
done: </span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
}
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> result
}
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> objIterator
}
}
</span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (const item of obj) {
console.log(</span>'atrrs:' + item + ',value:' +<span style="color: rgba(0, 0, 0, 1)"> obj)
}</span></pre>
</div>
<h2 class="ne-p">生成器函数写法</h2>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 为不可迭代的对象添加迭代器</span>
let obj =<span style="color: rgba(0, 0, 0, 1)"> {
a: </span>1<span style="color: rgba(0, 0, 0, 1)">,
b: </span>2<span style="color: rgba(0, 0, 0, 1)">
}
obj </span>= <span style="color: rgba(0, 0, 255, 1)">function</span>*<span style="color: rgba(0, 0, 0, 1)"> () {
let keys </span>=<span style="color: rgba(0, 0, 0, 1)"> Object.keys(obj);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">取到key值的长度</span>
let len =<span style="color: rgba(0, 0, 0, 1)"> keys.length;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义循环变量</span>
let n = 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">条件判断</span>
<span style="color: rgba(0, 0, 255, 1)">while</span> (n <= len - 1<span style="color: rgba(0, 0, 0, 1)">) {
yield { k: keys, v: obj] };
n</span>++<span style="color: rgba(0, 0, 0, 1)">
}
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">返回的是个对象的key和value</span>
<span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (let { k, v } of obj) {
console.log(k, v);
}</span></pre>
</div>
</div>
<p>其他相关如内置可迭代对象、用于可迭代对象的语法、接受可迭代对象的内置api 等 请点击 这里</p><br><br>
来源:https://www.cnblogs.com/longbensong/p/15217121.html
頁:
[1]