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