摘要:語法為回調(diào)函數(shù)擁有兩個(gè)參數(shù)第一個(gè)為對(duì)象的成員或數(shù)組的索引,第二個(gè)為對(duì)應(yīng)變量或內(nèi)容。但是對(duì)于的函數(shù),如果需要退出循環(huán)可使回調(diào)函數(shù)返回,其它返回值將被忽略。
each介紹JavaScript 專題系列第十一篇,講解 jQuery 通用遍歷方法 each 的實(shí)現(xiàn)
jQuery 的 each 方法,作為一個(gè)通用遍歷方法,可用于遍歷對(duì)象和數(shù)組。
語法為:
jQuery.each(object, [callback])
回調(diào)函數(shù)擁有兩個(gè)參數(shù):第一個(gè)為對(duì)象的成員或數(shù)組的索引,第二個(gè)為對(duì)應(yīng)變量或內(nèi)容。
// 遍歷數(shù)組 $.each( [0,1,2], function(i, n){ console.log( "Item #" + i + ": " + n ); }); // Item #0: 0 // Item #1: 1 // Item #2: 2
// 遍歷對(duì)象 $.each({ name: "John", lang: "JS" }, function(i, n) { console.log("Name: " + i + ", Value: " + n); }); // Name: name, Value: John // Name: lang, Value: JS退出循環(huán)
盡管 ES5 提供了 forEach 方法,但是 forEach 沒有辦法中止或者跳出 forEach 循環(huán),除了拋出一個(gè)異常。但是對(duì)于 jQuery 的 each 函數(shù),如果需要退出 each 循環(huán)可使回調(diào)函數(shù)返回 false,其它返回值將被忽略。
$.each( [0, 1, 2, 3, 4, 5], function(i, n){ if (i > 2) return false; console.log( "Item #" + i + ": " + n ); }); // Item #0: 0 // Item #1: 1 // Item #2: 2第一版
那么我們?cè)撛趺磳?shí)現(xiàn)這樣一個(gè) each 方法呢?
首先,我們肯定要根據(jù)參數(shù)的類型進(jìn)行判斷,如果是數(shù)組,就調(diào)用 for 循環(huán),如果是對(duì)象,就使用 for in 循環(huán),有一個(gè)例外是類數(shù)組對(duì)象,對(duì)于類數(shù)組對(duì)象,我們依然可以使用 for 循環(huán)。
更多關(guān)于類數(shù)組對(duì)象的知識(shí),我們可以查看《JavaScript專題之類數(shù)組對(duì)象與arguments》
那么又該如何判斷類數(shù)組對(duì)象和數(shù)組呢?實(shí)際上,我們?cè)凇禞avaScript專題之類型判斷(下)》就講過jQuery 數(shù)組和類數(shù)組對(duì)象判斷函數(shù) isArrayLike 的實(shí)現(xiàn)。
所以,我們可以輕松寫出第一版:
// 第一版 function each(obj, callback) { var length, i = 0; if ( isArrayLike(obj) ) { length = obj.length; for ( ; i < length; i++ ) { callback(i, obj[i]) } } else { for ( i in obj ) { callback(i, obj[i]) } } return obj; }中止循環(huán)
現(xiàn)在已經(jīng)可以遍歷對(duì)象和數(shù)組了,但是依然有一個(gè)效果沒有實(shí)現(xiàn),就是中止循環(huán),按照 jQuery each 的實(shí)現(xiàn),當(dāng)回調(diào)函數(shù)返回 false 的時(shí)候,我們就中止循環(huán)。這個(gè)實(shí)現(xiàn)起來也很簡單:
我們只用把:
callback(i, obj[i])
替換成:
if (callback(i, obj[i]) === false) { break; }
輕松實(shí)現(xiàn)中止循環(huán)的功能。
this我們?cè)趯?shí)際的開發(fā)中,我們有時(shí)會(huì)在 callback 函數(shù)中用到 this,先舉個(gè)不怎么恰當(dāng)?shù)睦樱?/p>
// 我們給每個(gè)人添加一個(gè) age 屬性,age 的值為 18 + index var person = [ {name: "kevin"}, {name: "daisy"} ] $.each(person, function(index, item){ this.age = 18 + index; }) console.log(person)
這個(gè)時(shí)候,我們就希望 this 能指向當(dāng)前遍歷的元素,然后給每個(gè)元素添加 age 屬性。
指定 this,我們可以使用 call 或者 apply,其實(shí)也很簡單:
我們把:
if (callback(i, obj[i]) === false) { break; }
替換成:
if (callback.call(obj[i], i, obj[i]) === false) { break; }
關(guān)于 this,我們?cè)倥e個(gè)常用的例子:
$.each($("p"), function(){ $(this).hover(function(){ ... }); })
雖然我們經(jīng)常會(huì)這樣寫:
$("p").each(function(){ $(this).hover(function(){ ... }); })
但是因?yàn)?$("p").each() 方法是定義在 jQuery 函數(shù)的 prototype 對(duì)象上面的,而 $.data()方法是定義 jQuery 函數(shù)上面的,調(diào)用的時(shí)候不從復(fù)雜的 jQuery 對(duì)象上調(diào)用,速度快得多。所以我們推薦使用第一種寫法。
回到第一種寫法上,就是因?yàn)閷?this 指向了當(dāng)前 DOM 元素,我們才能使用 $(this)將當(dāng)前 DOM 元素包裝成 jQuery 對(duì)象,優(yōu)雅的使用 hover 方法。
所以最終的 each 源碼為:
function each(obj, callback) { var length, i = 0; if (isArrayLike(obj)) { length = obj.length; for (; i < length; i++) { if (callback.call(obj[i], i, obj[i]) === false) { break; } } } else { for (i in obj) { if (callback.call(obj[i], i, obj[i]) === false) { break; } } } return obj; }性能比較
我們?cè)谛阅苌媳容^下 for 循環(huán)和 each 函數(shù):
var arr = Array.from({length: 1000000}, (v, i) => i); console.time("for") var i = 0; for (; i < arr.length; i++) { i += arr[i]; } console.timeEnd("for") console.time("each") var j = 0; $.each(arr, function(index, item){ j += item; }) console.timeEnd("each")
這里顯示一次運(yùn)算的結(jié)果:
從上圖可以看出,for 循環(huán)的性能是明顯好于 each 函數(shù)的,each 函數(shù)本質(zhì)上也是用的 for 循環(huán),到底是慢在了哪里呢?
我們?cè)倏匆粋€(gè)例子:
function each(obj, callback) { var i = 0; var length = obj.length for (; i < length; i++) { value = callback(i, obj[i]); } } function eachWithCall(obj, callback) { var i = 0; var length = obj.length for (; i < length; i++) { value = callback.call(obj[i], i, obj[i]); } } var arr = Array.from({length: 1000000}, (v, i) => i); console.time("each") var i = 0; each(arr, function(index, item){ i += item; }) console.timeEnd("each") console.time("eachWithCall") var j = 0; eachWithCall(arr, function(index, item){ j += item; }) console.timeEnd("eachWithCall")
這里顯示一次運(yùn)算的結(jié)果:
each 函數(shù)和 eachWithCall 函數(shù)唯一的區(qū)別就是 eachWithCall 調(diào)用了 call,從結(jié)果我們可以推測(cè)出,call 會(huì)導(dǎo)致性能損失,但也正是 call 的存在,我們才能將 this 指向循環(huán)中當(dāng)前的元素。
有舍有得吧。
專題系列JavaScript專題系列目錄地址:https://github.com/mqyqingfeng/Blog。
JavaScript專題系列預(yù)計(jì)寫二十篇左右,主要研究日常開發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖、節(jié)流、去重、類型判斷、拷貝、最值、扁平、柯里、遞歸、亂序、排序等,特點(diǎn)是研(chao)究(xi) underscore 和 jQuery 的實(shí)現(xiàn)方式。
如果有錯(cuò)誤或者不嚴(yán)謹(jǐn)?shù)牡胤?,?qǐng)務(wù)必給予指正,十分感謝。如果喜歡或者有所啟發(fā),歡迎 star,對(duì)作者也是一種鼓勵(lì)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/84603.html
摘要:專題系列共計(jì)篇,主要研究日常開發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖節(jié)流去重類型判斷拷貝最值扁平柯里遞歸亂序排序等,特點(diǎn)是研究專題之函數(shù)組合專題系列第十六篇,講解函數(shù)組合,并且使用柯里化和函數(shù)組合實(shí)現(xiàn)模式需求我們需要寫一個(gè)函數(shù),輸入,返回。 JavaScript 專題之從零實(shí)現(xiàn) jQuery 的 extend JavaScritp 專題系列第七篇,講解如何從零實(shí)現(xiàn)一個(gè) jQuery 的 ext...
摘要:寫在前面專題系列是我寫的第二個(gè)系列,第一個(gè)系列是深入系列。專題系列自月日發(fā)布第一篇文章,到月日發(fā)布最后一篇,感謝各位朋友的收藏點(diǎn)贊,鼓勵(lì)指正。 寫在前面 JavaScript 專題系列是我寫的第二個(gè)系列,第一個(gè)系列是 JavaScript 深入系列。 JavaScript 專題系列共計(jì) 20 篇,主要研究日常開發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖、節(jié)流、去重、類型判斷、拷貝、最值、扁平、柯里...
摘要:因?yàn)樵谖⑿判〕绦蛑?,和都是,加上又?qiáng)制使用嚴(yán)格模式,為,掛載就會(huì)發(fā)生錯(cuò)誤,所以就有人又發(fā)了一個(gè),代碼變成了這就是現(xiàn)在的樣子。 前言 在 《JavaScript 專題系列》 中,我們寫了很多的功能函數(shù),比如防抖、節(jié)流、去重、類型判斷、扁平數(shù)組、深淺拷貝、查找數(shù)組元素、通用遍歷、柯里化、函數(shù)組合、函數(shù)記憶、亂序等,可以我們?cè)撊绾谓M織這些函數(shù),形成自己的一個(gè)工具函數(shù)庫呢?這個(gè)時(shí)候,我們就要借...
摘要:一個(gè)經(jīng)常會(huì)看到的函數(shù)的實(shí)現(xiàn)為第一版我們可以這樣使用或者或者已經(jīng)有柯里化的感覺了,但是還沒有達(dá)到要求,不過我們可以把這個(gè)函數(shù)用作輔助函數(shù),幫助我們寫真正的函數(shù)。 JavaScript 專題系列第十三篇,講解函數(shù)柯里化以及如何實(shí)現(xiàn)一個(gè) curry 函數(shù) 定義 維基百科中對(duì)柯里化 (Currying) 的定義為: In mathematics and computer science, cu...
摘要:前端日?qǐng)?bào)精選專題之通用遍歷方法的實(shí)現(xiàn)深入了解的子組件上最流行的項(xiàng)目再聊移動(dòng)端頁面的適配譯盒子模型實(shí)踐教程中文全棧第天數(shù)據(jù)驅(qū)動(dòng)龍?jiān)迫珬Wg年開發(fā)趨勢(shì)瘋狂的技術(shù)宅在翻譯譯閉包并不神秘前端心得拼多多前端筆試個(gè)人文章容器技術(shù)方 2017-08-03 前端日?qǐng)?bào) 精選 JavaScript專題之jQuery通用遍歷方法each的實(shí)現(xiàn)深入了解React的子組件GitHub上最流行的Top 10 Jav...
閱讀 3552·2021-09-06 15:13
閱讀 1535·2021-09-02 10:19
閱讀 2482·2019-08-30 15:52
閱讀 929·2019-08-29 15:25
閱讀 1577·2019-08-26 18:36
閱讀 505·2019-08-26 13:23
閱讀 1345·2019-08-26 10:46
閱讀 3510·2019-08-26 10:41