摘要:引用自可迭代對象和迭代器不以規(guī)矩,不成方圓為了使某個(gè)對象成為可迭代對象象,它必須實(shí)現(xiàn)方法,也就是說,它得有一個(gè)是的屬性。的遍歷,絕對應(yīng)該用。
pseudojQuery 對象是偽數(shù)組 兩個(gè)事實(shí)英 ["sju:d??] 美 ["su:do?]
pseudo-array
adj.假的,虛偽的
n.[口]假冒的人,偽君子英 [s"ju:d???r"e?] 美 [s"ju:d???r"e?]
[計(jì)] 偽數(shù)組
不管以前知道不知道,至少馬上會知道
jQuery 對象是一個(gè)偽數(shù)組。
var $obj = jQuery(); Array.isArray($obj); // false
jQuery.fn 是 jQuery.prototype 的簡寫
jQuery.fn === jQuery.prototype; // true提出問題
既然 jQuery 對象是偽數(shù)組,那 ES6 的 for...of 想用在 jQuery 對象上就不會那么順利。畢竟 jQuery 還沒有按 ES6 重寫。
那么,想用 for..of 遍歷 jQuery 對象中的 DOM 引用,就自己實(shí)現(xiàn)吧——這得從 iterable 和 iterator 開始。
iterable(可迭代對象) 和 iterator(迭代器) 不以規(guī)矩,不成方圓The for...of statement creates a loop Iterating over iterable objects (including Array, Map, Set, arguments object and so on), invoking a custom iteration hook with statements to be executed for the value of each distinct property.
引用自:for...of statement | MDN
為了使某個(gè)對象成為可迭代對象象,它必須實(shí)現(xiàn) @@iterator 方法,也就是說,它得有一個(gè) key 是 Symbol.iterator 的屬性。說人話,就是必須得實(shí)現(xiàn)這么個(gè)東東:
jQuery.fn[Symbol.iterator] = ....
而這個(gè)所謂的 @@iterator 方法,返回的是一個(gè)迭代器。迭代器這活也不是隨便誰都能干的,它必須得有一個(gè) next() 方法,而這個(gè) next() 方法每次調(diào)用,都返回下一個(gè)迭代對象。
當(dāng)然迭代對象也是有標(biāo)準(zhǔn)的,它必須是這么個(gè)結(jié)構(gòu):
{ done: "(boolean),true 表示迭代完成,false 表示還有下一個(gè)", value: "這個(gè)才是正主,for...of 迭代出來的值" }
注意 done 這個(gè)小坑,其它語言中通常是用 hasNext() 或者 hasMore() 之類的來判斷是否有下一個(gè)值,而 javascript 是用 done 來判斷,它們的邏輯意思正好相反,所以千萬注意不要給錯(cuò)了值。
實(shí)現(xiàn)注:Symbol 是 ES6 中引入的新的鍵類型。之前的鍵類型只能是字符串,而在 ES6 中,有兩種了。關(guān)于 Symbol,可以參閱 【探秘ES6】系列專欄(八):JS的第七種基本類型Symbols 和 Symbol - JavaScript | MDN
知道了規(guī)矩,實(shí)現(xiàn)起來就好辦了
jQuery.fn[Symbol.iterator] = function() { return (function(_this) { var index = 0; return { next: function() { return { done: index >= _this.length, value: _this[index++] }; } }; })(this); };測試
for (var dom in $("div")) { console.log(dom); }
正確執(zhí)行,通過……話雖如此,代碼寫起來好累。所以,其實(shí)應(yīng)該用 Generator……
GeneratorES6 的又一新特性,Generator 對象(生成器對象),簡直就是為迭代而生的。每個(gè)生成器對象都符合上面提到的 iterable 和 iterator 兩個(gè)規(guī)矩。換句話說,生成器對象既是一個(gè)可迭代對象,又是一個(gè)迭代器,而它作為可迭代對象的時(shí)候,返回的迭代器就是它自己。
然而生成器對象并不是 new 出來的,而是通過 generator function(生成器函數(shù))生成的;生成器函數(shù)得自己寫,又不能 new Generator(),那么這個(gè)生成器對象從哪里來呢?當(dāng)然是生成器函數(shù)生成的,而且這會用到新語法,以及新的關(guān)鍵字 yield。
generator function(生成器函數(shù))和 yield生成器函數(shù)的定義與普通函數(shù)略有不同,形式上的區(qū)別是,它在 function 關(guān)鍵字后加了一個(gè) * 號,就像這樣:
function *aGenerator() { ... }
生成器函數(shù)在內(nèi)容上的區(qū)別就是,它的內(nèi)容其實(shí)并不是它自己的內(nèi)容,而是描述了它產(chǎn)生生成器對象的行為。
有點(diǎn)亂,來捋一捋:
生成器函數(shù)返回一個(gè)生成器對象
生成器對象是一個(gè)迭代器
生成器對象也是一個(gè)可迭代對象,每次迭代返回自己(這句暫時(shí)忽略)
迭代器有一個(gè) next() 方法用來返回迭代值(以及判斷是否完成迭代)
捋清楚了,來說生成器函數(shù)的內(nèi)容——其實(shí)就是干上面最后一條描述的事情:描述每次迭代返回的值,以及是否完成迭代。這是與普通 function 完全不同的語法,它是怎么做到的呢?憑空說起來太吃力,先上代碼
function *aGenerator() { yield 1; yield 2; yield 3; }
每次 yield,就相當(dāng)于一次通過 next() 返回值,也就上面提到的迭代對象的 value 屬性。那么 done 屬性如何確定呢?如果從生成器函數(shù)返回,就 done 了。這有兩種情況,一種是自然執(zhí)行完所有語法,函數(shù)結(jié)束返回;另一種是在函數(shù)體中調(diào)用 return 返回。
新問題:眼看例中 3 個(gè) yield 語句排在一起,不是“啪啪啪”一下子就搞完了?最后就 next() 出來一個(gè) 3 了事?
非也,yield 返回值與 return 不同。yield 反回值(也就是 next())之后會將代碼暫停在那個(gè)位置,等下一次 next() 的時(shí)候,繼續(xù)執(zhí)行,到下一個(gè) yield 再暫?!绱酥钡斤@示或隱匿的 return。
改進(jìn)的 jQuery.fn[Symbol.iterator]jQuery.fn[Symbol.iterator] = function*() { for (var i = 0; i < this.length; i++) { yield this[i]; } };
比上一個(gè)實(shí)現(xiàn)簡單了不少吧,但是你以為這是最簡單的么……
巧妙的實(shí)現(xiàn) 更簡單的實(shí)現(xiàn)除了可以用 yield 返回值之外,還可以用 yield *返回可迭代對象。這時(shí),控制權(quán)會暫時(shí)交給這個(gè)可迭代對象,由它接替實(shí)現(xiàn) next(),直到 done,再由當(dāng)前生成器函數(shù)中的下一個(gè) yield 接手繼續(xù)。形象一點(diǎn)的理解——這個(gè)過程有點(diǎn)像樹型結(jié)構(gòu)的深度遍歷。
因?yàn)樵鷶?shù)組也是可迭代對象,所以可以取個(gè)巧
jQuery.fn[Symbol.iterator] = function*() { yield *[].slice.call(this); };最簡單的實(shí)現(xiàn)
上面說了一通,用了 N 種方法,無非是講解 ES6 的新特性而已。要為 jQuery 實(shí)現(xiàn) for...of 遍歷,最簡單的方法其實(shí)是拿來主義:
jQuery.fn[Symbol.iterator] = [][Symbol.iterator];最后的提醒
jQuery 對象是一個(gè)偽數(shù)組,它的每一個(gè)元素都是一個(gè) DOM(或原對象)而不是被封裝的 jQuery 對象,所以,用 for..of 遍歷的時(shí)候,和用 jQuery.fn.each() 遍歷一樣,如果想繼續(xù)在每個(gè)元素上使用 jQuery 的特性,就要記得用 jQuery() 包裝。
// for...of for (var dom in $("span")) { var $span = $(dom); } // jQuey.fn.each $("span").each(function() { var $span = $(this); });鄭重致歉
其實(shí),我不小心又騙了大家。jQuery 壓根沒有實(shí)現(xiàn) for...of 的必要,即使沒有 ES6,用 for...in 遍歷 jQuery 對象也是一件很悲催的事情,不信你試試。
jQuery 的遍歷,絕對應(yīng)該用 jQuery.fn.each()。
但是,看在我要以此為例來說 ES6 的幾樣新特性的份上,原諒我吧!^_^!
參考ECMAScript 6 Features
Iteration protocls - JavaScript | MDN
Generator - JavaScript | MDN
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/85945.html
摘要:系列公用委托都用于委托帶有返回值的的方法,所有都是最后一個(gè)參數(shù)代表返回值類型。的字面對象據(jù)稱也是哈希實(shí)現(xiàn)。 Java 丟了好多年,最近在揀起來,首先當(dāng)然是了解這么多年來它的變化,于是發(fā)現(xiàn)了 Java 8 的java.util.stream。在學(xué)習(xí)和試驗(yàn)的過程中,相比較于 C# 和 javascript,有那么些心得,作文以記之。 早些時(shí)間寫過一篇《ES6 的 for..of 和 Ge...
摘要:系列公用委托都用于委托帶有返回值的的方法,所有都是最后一個(gè)參數(shù)代表返回值類型。的字面對象據(jù)稱也是哈希實(shí)現(xiàn)。 Java 丟了好多年,最近在揀起來,首先當(dāng)然是了解這么多年來它的變化,于是發(fā)現(xiàn)了 Java 8 的java.util.stream。在學(xué)習(xí)和試驗(yàn)的過程中,相比較于 C# 和 javascript,有那么些心得,作文以記之。 早些時(shí)間寫過一篇《ES6 的 for..of 和 Ge...
摘要:本文從使用對數(shù)組進(jìn)行遍歷開始說起,粗略對比使用進(jìn)行遍歷的差異,并由此引入中可迭代對象迭代器的概念,并對其進(jìn)行粗略介紹。說到這里,就繼續(xù)說一下迭代器關(guān)閉的情況了。確實(shí),符合可迭代協(xié)議和迭代器協(xié)議的。 本文從使用 forEach 對數(shù)組進(jìn)行遍歷開始說起,粗略對比使用 forEach , for...in , for...of 進(jìn)行遍歷的差異,并由此引入 ES6 中 可迭代對象/迭代器 的概...
摘要:文章內(nèi)容分兩部分前半部分為迭代器模式概念后半部分為中迭代器上半部分開始迭代器模式提供一種方法順序訪問一個(gè)聚合對象中的各個(gè)元素,而又不需要暴露該對象的內(nèi)部表示。下半部分開始的迭代器迭代器等同于遍歷器。執(zhí)行該函數(shù),會返回一個(gè)遍歷器對象。 showImg(https://segmentfault.com/img/bVbuyaZ?w=800&h=600); 文章內(nèi)容分兩部分: 前半部分為 迭...
摘要:當(dāng)這個(gè)迭代器的方法被首次后續(xù)調(diào)用時(shí),其內(nèi)的語句會執(zhí)行到第一個(gè)后續(xù)出現(xiàn)的位置為止,后緊跟迭代器要返回的值。在這個(gè)回調(diào)函數(shù)里,我們使用第一個(gè)請求返回的,再次發(fā)起一個(gè)請求。 寫在前面 本文首發(fā)于公眾號:符合預(yù)期的CoyPan 后續(xù)文章:【JS基礎(chǔ)】從JavaScript中的for...of說起(下) - async和await 先來看一段很常見的代碼: const arr = [1, 2, ...
閱讀 1801·2023-04-26 00:20
閱讀 1851·2021-11-08 13:21
閱讀 2049·2021-09-10 10:51
閱讀 1606·2021-09-10 10:50
閱讀 3334·2019-08-30 15:54
閱讀 2161·2019-08-30 14:22
閱讀 1457·2019-08-29 16:10
閱讀 3119·2019-08-26 11:50