pseudo
英 ['sju:d??] 美 ['su:do?]
adj.假的,虛偽的
n.[口]假冒的人,偽君子成都網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)介紹好的網(wǎng)站是理念、設(shè)計(jì)和技術(shù)的結(jié)合。創(chuàng)新互聯(lián)擁有的網(wǎng)站設(shè)計(jì)理念、多方位的設(shè)計(jì)風(fēng)格、經(jīng)驗(yàn)豐富的設(shè)計(jì)團(tuán)隊(duì)。提供PC端+手機(jī)端網(wǎng)站建設(shè),用營(yíng)銷思維進(jìn)行網(wǎng)站設(shè)計(jì)、采用先進(jìn)技術(shù)開源代碼、注重用戶體驗(yàn)與SEO基礎(chǔ),將技術(shù)與創(chuàng)意整合到網(wǎng)站之中,以契合客戶的方式做到創(chuàng)意性的視覺化效果。
pseudo-array
英 [s'ju:d???r'e?] 美 [s'ju:d???r'e?]
[計(jì)] 偽數(shù)組
不管以前知道不知道,至少馬上會(huì)知道
jQuery 對(duì)象是一個(gè)偽數(shù)組。
var $obj = jQuery();
Array.isArray($obj); // false
jQuery.fn
是 jQuery.prototype
的簡(jiǎn)寫
jQuery.fn === jQuery.prototype; // true
既然 jQuery 對(duì)象是偽數(shù)組,那 ES6 的 for...of 想用在 jQuery 對(duì)象上就不會(huì)那么順利。畢竟 jQuery 還沒有按 ES6 重寫。
那么,想用 for..of 遍歷 jQuery 對(duì)象中的 DOM 引用,就自己實(shí)現(xiàn)吧——這得從 iterable 和 iterator 開始。
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è)對(duì)象成為可迭代對(duì)象象,它必須實(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è)迭代對(duì)象。
當(dāng)然迭代對(duì)象也是有標(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ò)了值。
注: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……
ES6 的又一新特性,Generator 對(duì)象(生成器對(duì)象),簡(jiǎn)直就是為迭代而生的。每個(gè)生成器對(duì)象都符合上面提到的 iterable 和 iterator 兩個(gè)規(guī)矩。換句話說,生成器對(duì)象既是一個(gè)可迭代對(duì)象,又是一個(gè)迭代器,而它作為可迭代對(duì)象的時(shí)候,返回的迭代器就是它自己。
然而生成器對(duì)象并不是 new 出來的,而是通過 generator function(生成器函數(shù))生成的;生成器函數(shù)得自己寫,又不能 new Generator()
,那么這個(gè)生成器對(duì)象從哪里來呢?當(dāng)然是生成器函數(shù)生成的,而且這會(huì)用到新語法,以及新的關(guān)鍵字 yield
。
生成器函數(shù)的定義與普通函數(shù)略有不同,形式上的區(qū)別是,它在 function
關(guān)鍵字后加了一個(gè) *
號(hào),就像這樣:
function *aGenerator() { ... }
生成器函數(shù)在內(nèi)容上的區(qū)別就是,它的內(nèi)容其實(shí)并不是它自己的內(nèi)容,而是描述了它產(chǎn)生生成器對(duì)象的行為。
有點(diǎn)亂,來捋一捋:
next()
方法用來返回迭代值(以及判斷是否完成迭代)捋清楚了,來說生成器函數(shù)的內(nèi)容——其實(shí)就是干上面最后一條描述的事情:描述每次迭代返回的值,以及是否完成迭代。這是與普通 function
完全不同的語法,它是怎么做到的呢?憑空說起來太吃力,先上代碼
function *aGenerator() {
yield 1;
yield 2;
yield 3;
}
每次 yield
,就相當(dāng)于一次通過 next()
返回值,也就上面提到的迭代對(duì)象的 value
屬性。那么 done
屬性如何確定呢?如果從生成器函數(shù)返回,就 done 了。這有兩種情況,一種是自然執(zhí)行完所有語法,函數(shù)結(jié)束返回;另一種是在函數(shù)體中調(diào)用 return
返回。
新問題:眼看例中 3 個(gè) yield
語句排在一起,不是“啪啪啪”一下子就搞完了?最后就 next()
出來一個(gè) 3
了事?
非也,yield
返回值與 return
不同。yield
反回值(也就是 next()
)之后會(huì)將代碼暫停在那個(gè)位置,等下一次 next()
的時(shí)候,繼續(xù)執(zhí)行,到下一個(gè) yield
再暫?!绱酥钡斤@示或隱匿的 return
。
jQuery.fn[Symbol.iterator]
jQuery.fn[Symbol.iterator] = function*() {
for (var i = 0; i < this.length; i++) {
yield this[i];
}
};
比上一個(gè)實(shí)現(xiàn)簡(jiǎn)單了不少吧,但是你以為這是最簡(jiǎn)單的么……
除了可以用 yield
返回值之外,還可以用 yield *
返回可迭代對(duì)象。這時(shí),控制權(quán)會(huì)暫時(shí)交給這個(gè)可迭代對(duì)象,由它接替實(shí)現(xiàn) next()
,直到 done
,再由當(dāng)前生成器函數(shù)中的下一個(gè) yield
接手繼續(xù)。形象一點(diǎn)的理解——這個(gè)過程有點(diǎn)像樹型結(jié)構(gòu)的深度遍歷。
因?yàn)樵鷶?shù)組也是可迭代對(duì)象,所以可以取個(gè)巧
jQuery.fn[Symbol.iterator] = function*() {
yield *[].slice.call(this);
};
上面說了一通,用了 N 種方法,無非是講解 ES6 的新特性而已。要為 jQuery 實(shí)現(xiàn) for...of 遍歷,最簡(jiǎn)單的方法其實(shí)是拿來主義:
jQuery.fn[Symbol.iterator] = [][Symbol.iterator];
jQuery 對(duì)象是一個(gè)偽數(shù)組,它的每一個(gè)元素都是一個(gè) DOM(或原對(duì)象)而不是被封裝的 jQuery 對(duì)象,所以,用 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 壓根沒有必要為 for...of
實(shí)現(xiàn) iterator
。雖然用 for...in
遍歷 jQuery 對(duì)象也是一件很悲催的事情(不信你試試),但有 Array.from()
,還有 jQuery.fn.toArray()
啊。
但話說回來,jQuery 的遍歷,多數(shù)情況下還是應(yīng)該用 jQuery.fn.each()
。
但是,看在我要以此為例來說 ES6 的幾樣新特性的份上,原諒我吧!^_^!