摘要:本文同步自我得博客最近十幾天都在忙畢業(yè)論文的事,所以上一次為大家介紹完這個(gè)框架的結(jié)構(gòu)或者說(shuō)是這個(gè)框架的設(shè)計(jì)思路之后就一直沒(méi)動(dòng)靜了,今天我又滿血復(fù)活了,讓我們繼續(xù)來(lái)探索的源碼奧秘吧。
本文同步自我得博客:http://www.joeray61.com
最近十幾天都在忙畢業(yè)論文的事,所以上一次為大家介紹完underscore這個(gè)框架的結(jié)構(gòu)(或者說(shuō)是這個(gè)框架的設(shè)計(jì)思路)之后就一直沒(méi)動(dòng)靜了,今天我又滿血復(fù)活了,讓我們繼續(xù)來(lái)探索underscore的源碼奧秘吧。
沒(méi)看過(guò)上一篇文章的朋友可以戳這里:underscore源碼解析(一)
今天的內(nèi)容是underscore里面封裝的一些函數(shù),我將逐個(gè)介紹,咱們直接入正題吧
var each = _.each = _.forEach = function(obj, iterator, context) { // 不處理空值 if(obj == null) return; if(nativeForEach && obj.forEach === nativeForEach) { // 如果宿主環(huán)境支持, 則優(yōu)先調(diào)用JavaScript 1.6提供的forEach方法 obj.forEach(iterator, context); } else if(obj.length === +obj.length) { // 對(duì)[數(shù)組]中每一個(gè)元素執(zhí)行處理器方法 for(var i = 0, l = obj.length; i < l; i++) { if( i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; } } else { // 對(duì){對(duì)象}中每一個(gè)元素執(zhí)行處理器方法 for(var key in obj) { if(_.has(obj, key)) { if(iterator.call(context, obj[key], key, obj) === breaker) return; } } } };
這個(gè)函數(shù)的實(shí)現(xiàn)思想其實(shí)很簡(jiǎn)單,如果宿主環(huán)境(一般為瀏覽器或者node.js)支持原生的forEach方法,就調(diào)用原生的,否則就遍歷該數(shù)組或者對(duì)象,依次調(diào)用處理器方法
值得一提的是在判斷是否是數(shù)組的時(shí)候,這里的代碼為
obj.length === +obj.length
這其實(shí)是一種鴨式辨型的判定方法,具體可以參見(jiàn)我在SF上提過(guò)的一個(gè)問(wèn)題:點(diǎn)我
_.map / _.collect_.map = _.collect = function(obj, iterator, context) { // 用于存放返回值的數(shù)組 var results = []; if(obj == null) return results; // 優(yōu)先調(diào)用宿主環(huán)境提供的map方法 if(nativeMap && obj.map === nativeMap) return obj.map(iterator, context); // 迭代處理集合中的元素 each(obj, function(value, index, list) { // 將每次迭代處理的返回值存儲(chǔ)到results數(shù)組 results[results.length] = iterator.call(context, value, index, list); }); // 返回處理結(jié)果 if(obj.length === +obj.length) results.length = obj.length; return results; };
map/collect函數(shù)與each的區(qū)別在于map/collect會(huì)存儲(chǔ)每次迭代的返回值, 并作為一個(gè)新的數(shù)組返回
_.reduce / _.foldl / _.inject_.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { // 通過(guò)參數(shù)數(shù)量檢查是否存在初始值 var initial = arguments.length > 2; if(obj == null) obj = []; // 優(yōu)先調(diào)用宿主環(huán)境提供的reduce方法 if(nativeReduce && obj.reduce === nativeReduce && false) { if(context) iterator = _.bind(iterator, context); return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); } // 迭代處理集合中的元素 each(obj, function(value, index, list) { if(!initial) { // 如果沒(méi)有初始值, 則將第一個(gè)元素作為初始值; 如果被處理的是對(duì)象集合, 則默認(rèn)值為第一個(gè)屬性的值 memo = value; initial = true; } else { // 記錄處理結(jié)果, 并將結(jié)果傳遞給下一次迭代 memo = iterator.call(context, memo, value, index, list); } }); if(!initial) throw new TypeError("Reduce of empty array with no initial value"); return memo; };
這個(gè)函數(shù)的作用是將集合中每個(gè)元素放入迭代處理器, 并將本次迭代的返回值作為memo傳遞到下一次迭代, 一般用于累計(jì)結(jié)果或連接數(shù)據(jù)
_.reduceRight / _.foldr_.reduceRight = _.foldr = function(obj, iterator, memo, context) { var initial = arguments.length > 2; if(obj == null) obj = []; // 優(yōu)先調(diào)用宿主環(huán)境提供的reduceRight方法 if(nativeReduceRight && obj.reduceRight === nativeReduceRight) { if(context) iterator = _.bind(iterator, context); return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); } // 逆轉(zhuǎn)集合中的元素順序 var reversed = _.toArray(obj).reverse(); if(context && !initial) iterator = _.bind(iterator, context); // 通過(guò)reduce方法處理數(shù)據(jù) return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator); };
這個(gè)函數(shù)與reduce相似,不過(guò)它是逆向迭代集合中的元素
_.find / _.detect_.find = _.detect = function(obj, iterator, context) { // result存放第一個(gè)能夠通過(guò)驗(yàn)證的元素 var result; // 通過(guò)any方法遍歷數(shù)據(jù), 并記錄通過(guò)驗(yàn)證的元素 any(obj, function(value, index, list) { // 如果處理器返回的結(jié)果被轉(zhuǎn)換為Boolean類(lèi)型后值為true, 則記錄當(dāng)前值并返回當(dāng)前元素 if(iterator.call(context, value, index, list)) { result = value; return true; } }); return result; };
這個(gè)方法的作用是遍歷集合中的元素, 返回能夠通過(guò)處理器驗(yàn)證的第一個(gè)元素
_.filter / _.select_.filter = _.select = function(obj, iterator, context) { // 用于存儲(chǔ)通過(guò)驗(yàn)證的元素?cái)?shù)組 var results = []; if(obj == null) return results; // 優(yōu)先調(diào)用宿主環(huán)境提供的filter方法 if(nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); // 迭代集合中的元素, 并將通過(guò)處理器驗(yàn)證的元素放到數(shù)組中并返回 each(obj, function(value, index, list) { if(iterator.call(context, value, index, list)) results[results.length] = value; }); return results; };
這個(gè)方法與find作用類(lèi)似, 但它會(huì)記錄下集合中所有通過(guò)驗(yàn)證的元素
_.reject_.reject = function(obj, iterator, context) { var results = []; if(obj == null) return results; each(obj, function(value, index, list) { if(!iterator.call(context, value, index, list)) results[results.length] = value; }); return results; };
這個(gè)方法的代碼里面我沒(méi)有加注釋?zhuān)驗(yàn)檎麄€(gè)代碼與filter/select方法幾乎一樣,不同點(diǎn)在于向results數(shù)組里添加元素的時(shí)候判斷條件是相反的,也就是說(shuō)這個(gè)方法的作用是返回沒(méi)有通過(guò)處理器驗(yàn)證的元素列表
_.every / _.all_.every = _.all = function(obj, iterator, context) { var result = true; if(obj == null) return result; // 優(yōu)先調(diào)用宿主環(huán)境提供的every方法 if(nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); // 迭代集合中的元素 each(obj, function(value, index, list) { // 這里我不太理解,為什么藥寫(xiě)成 result = (result && iterator.call(context, value, index, list)) 而不是 result = iterator.call(context, value, index, list) if(!( result = result && iterator.call(context, value, index, list))) return breaker; }); return !!result; };
這個(gè)方法的作用是如果集合中所有元素均能通過(guò)處理器驗(yàn)證, 則返回true
any / _.some / _.anyvar any = _.some = _.any = function(obj, iterator, context) { // 如果沒(méi)有指定處理器參數(shù), 則使用默認(rèn)的處理器函數(shù),該函數(shù)會(huì)返回參數(shù)本身 iterator || ( iterator = _.identity); var result = false; if(obj == null) return result; // 優(yōu)先調(diào)用宿主環(huán)境提供的some方法 if(nativeSome && obj.some === nativeSome) return obj.some(iterator, context); // 迭代集合中的元素 each(obj, function(value, index, list) { if(result || ( result = iterator.call(context, value, index, list))) return breaker; }); return !!result; };
該函數(shù)的作用是檢查集合中是否有任何一個(gè)元素在被轉(zhuǎn)換成Boolean類(lèi)型時(shí)是否為true
_.include / _.contains_.include = _.contains = function(obj, target) { var found = false; if(obj == null) return found; // 優(yōu)先調(diào)用宿主環(huán)境提供的Array.prototype.indexOf方法 if(nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; // 通過(guò)any方法迭代集合中的元素, 驗(yàn)證元素的值和類(lèi)型與目標(biāo)是否完全匹配 found = any(obj, function(value) { return value === target; }); return found; };
這個(gè)函數(shù)用于檢查集合中是否有值與目標(biāo)參數(shù)完全匹配,包括數(shù)據(jù)類(lèi)型
小結(jié)今天先介紹以上10個(gè)函數(shù)的實(shí)現(xiàn)細(xì)節(jié),之后還會(huì)繼續(xù)帶來(lái)其他函數(shù)的介紹,歡迎大家提出指正和建議,thx for reading, hope u enjoy
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/78161.html
摘要:本文同步自我得博客我在這個(gè)系列的第一篇文章說(shuō)過(guò),我學(xué)是為了在學(xué)的時(shí)候少一些阻礙,從第一篇的寫(xiě)作時(shí)間到今天,大概也有個(gè)十幾二十天,感覺(jué)拖得有點(diǎn)久,所以今天將會(huì)是源碼解析系列的最后一篇文章,我會(huì)在這篇文章中介紹剩下的所有函數(shù)。 本文同步自我得博客:http://www.joeray61.com 我在這個(gè)系列的第一篇文章說(shuō)過(guò),我學(xué)underscore是為了在學(xué)backbone的時(shí)候少一些阻礙...
摘要:本文同步自我得博客最近準(zhǔn)備折騰一下,在事先了解了之后,我知道了對(duì)這個(gè)庫(kù)有著強(qiáng)依賴,正好之前也沒(méi)使用過(guò),于是我就想先把徹底了解一下,這樣之后折騰的時(shí)候也少一點(diǎn)阻礙。 本文同步自我得博客:http://www.joeray61.com 最近準(zhǔn)備折騰一下backbone.js,在事先了解了backbone之后,我知道了backbone對(duì)underscore這個(gè)庫(kù)有著強(qiáng)依賴,正好undersc...
摘要:本文同步自我得博客前兩天在微博上看到的微博推薦了我的前兩篇文章,有點(diǎn)意外和驚喜。沒(méi)看過(guò)前兩篇博客的朋友可以戳這里源碼解析一源碼解析二上一篇文章介紹了的個(gè)函數(shù)的具體實(shí)現(xiàn)細(xì)節(jié),今天將繼續(xù)介紹其他的函數(shù)。 本文同步自我得博客:http://www.joeray61.com 前兩天在微博上看到SF的微博推薦了我的前兩篇文章,有點(diǎn)意外和驚喜。作為一個(gè)菜鳥(niǎo),真的是倍受鼓舞,我寫(xiě)博客的動(dòng)力也更充足了...
說(shuō)明1、源碼結(jié)構(gòu)通覽,簡(jiǎn)單注釋說(shuō)明2、通過(guò)調(diào)用方法講解核心代碼邏輯 一、源碼的結(jié)構(gòu) 為了方便比對(duì)源碼,按源碼的結(jié)構(gòu)順序展示。underscore是個(gè)輕量級(jí)的工具庫(kù),大部分代碼是實(shí)現(xiàn)特定功能以函數(shù)的形式存在,本身會(huì)比較簡(jiǎn)單,沒(méi)對(duì)方法具體說(shuō)明,可直接參考underscore中文文檔 (function() { var root = this; var previousUnderscore = ...
摘要:創(chuàng)建一個(gè)全局對(duì)象在瀏覽器中表示為對(duì)象在中表示對(duì)象保存下劃線變量被覆蓋之前的值如果出現(xiàn)命名沖突或考慮到規(guī)范可通過(guò)方法恢復(fù)被占用之前的值并返回對(duì)象以便重新命名創(chuàng)建一個(gè)空的對(duì)象常量便于內(nèi)部共享使用將內(nèi)置對(duì)象的原型鏈緩存在局部變量方便快速調(diào)用將 // Underscore.js 1.3.3 // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc....
閱讀 2465·2021-11-22 09:34
閱讀 3072·2021-10-25 09:43
閱讀 1987·2021-10-11 10:59
閱讀 3396·2021-09-22 15:13
閱讀 2334·2021-09-04 16:40
閱讀 426·2019-08-30 15:53
閱讀 3196·2019-08-30 11:13
閱讀 2610·2019-08-29 17:30