摘要:傳入值進行判斷以此決定函數,將三個參數包括回調傳入中其中回調函數充當迭代器進行真值檢測,最后。是從一個中隨機返回值,并且返回值受限于這個參數,如果沒有傳入或者傳入了則執(zhí)行語句,目的是將判斷處理之后返回單一值。
今天繼續(xù)上次的內容,之前我們講到了 reduce 的用法,其實我覺得用法倒是其次的關鍵是作者實現(xiàn) reduce 過程中所靈活用到的函數處理方法,我們只要有心稍加總覺完全可以拿來主義,豐富自己的代碼└(^o^)┘。
_.find = _.detect = function(obj, predicate, context) { var keyFinder = isArrayLike(obj) ? _.findIndex : _.findKey; var key = keyFinder(obj, predicate, context); if (key !== void 0 && key !== -1) return obj[key]; };
_.find,討論這個函數首先要弄懂 _.findIndex 和 _.findKey,這里我們先簡單知道一個是針對數組一個是針對對象,具體的后面讀到源碼再說。傳入值 obj 進行 isArrayLike 判斷以此決定 keyFinder 函數,將三個參數包括回調傳入 keyFinder 中其中 predicate 回調函數充當迭代器進行真值檢測,最后 return obj[key]。
var createPredicateIndexFinder = function(dir) { return function(array, predicate, context) { predicate = cb(predicate, context); var length = getLength(array); var index = dir > 0 ? 0 : length - 1; for (; index >= 0 && index < length; index += dir) { if (predicate(array[index], index, array)) return index; } return -1; }; };
以 _.findIndex 為例簡單介紹一下,_.findIndex 是由 createPredicateIndexFinder 包裝而成,意義在于返回 predicate 函數內部 return true。
_.filter = _.select = function(obj, predicate, context) { var results = []; predicate = cb(predicate, context); _.each(obj, function(value, index, list) { if (predicate(value, index, list)) results.push(value); }); return results; };
_.filter 函數與 _.find 類似,內部實現(xiàn)較之 _.find 更簡單些,_.find 意為匹配 predicate 回調 return true 唯一就近值,_.filter 則是匹配所有值的集合。那么有人說為什么不用 _.filter()[0] 取代 _.find,理論上二者確實是相同值,但是 _.filter 會遍歷傳參 obj 直至結束,而 _.find 則是遍歷過程中匹配成功結束遍歷,所以某些情況下 _.find 優(yōu)于 _.filter。
_.reject = function(obj, predicate, context) { return _.filter(obj, _.negate(cb(predicate)), context); };
_.reject,通過 _.negate 和 cb 函數包裝 predicate 回調,實際上就是用 optimizeCb 優(yōu)化 predicate function,然后用 _.negate 返回與 predicate 相反的 Boolean 類型值,以此獲得與 _.filter 作用相反的結果集合。
_.every = _.all = function(obj, predicate, context) { predicate = cb(predicate, context); var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length; for (var index = 0; index < length; index++) { var currentKey = keys ? keys[index] : index; if (!predicate(obj[currentKey], currentKey, obj)) return false; } return true; };
_.every,我們看源碼中的返回值類型為 Boolean 知道這是一個用于真值檢測的函數,內部的處理步驟已經很程序化了,首先優(yōu)化回調函數 predicate,處理傳參 obj(根據 Object 或者 Array),回調中接收 obj[currentKey], currentKey, obj 三個參數進行 Boolean 判斷,當判斷失敗的時候則 if (!false) return false; 結束 for 循環(huán)。這個方法看上去很雞肋,但實際上結合 predicate 回調應用于某些判斷處理很給力。
_.some = _.any = function(obj, predicate, context) { predicate = cb(predicate, context); var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length; for (var index = 0; index < length; index++) { var currentKey = keys ? keys[index] : index; if (predicate(obj[currentKey], currentKey, obj)) return true; } return false; };
_.some,看源碼我們可以知道它基本上與 _.every 類似,區(qū)別在于 _.some 遍歷 obj 過程中只要任何一個元素通過 predicate 回調的真值檢測就直接立即中斷遍歷并返回 true。我主觀意識上更偏向于 _.every 和 _.some 用一個相同的基礎函數包裝再通過判斷值構建它們,就像 createReduce 函數構成 _.reduce、_.reduceRight 一樣,但是不知道作者為什么沒有這樣做,可能有其他的考慮吧,這里不再揣測。
_.contains = _.includes = _.include = function(obj, item, fromIndex, guard) { if (!isArrayLike(obj)) obj = _.values(obj); if (typeof fromIndex != "number" || guard) fromIndex = 0; return _.indexOf(obj, item, fromIndex) >= 0; };
_.contains 用于檢查 obj 中是否包含 item 值,我更傾向于這是一個簡化版的 _.some,如果是我寫基礎函數可能真的就只有 _.some 不用 _.contains,但是 Undescore.js 作為一個知名函數庫,在代碼優(yōu)化的執(zhí)行速度上肯定要比我們做的更細。
這里順便說一下 _.indexOf 和 guard,_.indexOf 是由 createIndexFinder 包裝而來,可以理解為數組版的 indexOf,indexOf 概念可參考 String.prototype.indexOf() 和 Array.prototype.indexOf()。關于 array.indexOf(searchElement[, fromIndex = 0]),我這里再說幾句,這個 JAVASCRIPT 函數傳入1或2個參數,第一個參數為將要進行匹配的內容,可為 Number 可為 String,第二個可選參數為(需要定向匹配數組中某一值的數組下標值 - array.length)*n,且 n!= 0,array.indexOf 根據這個下標進行定向匹配驗證,如果匹配成功則返回值為被匹配值的數組下標,匹配失敗則返回 -1。
var array = [2, 9, 9,9,9,3,4]; undefined array.indexOf(9,2); 2 array.indexOf(9,3); 3 array.indexOf(9,4); 4 array.indexOf(9,5); -1 array.indexOf(3,5); 5 array.indexOf(5); -1 array.indexOf(2, -7); 0
_.indexOf 雖然與 array.indexOf(searchElement[, fromIndex = 0]) 有所區(qū)別,但也有很多相通之處。
_.invoke = restArgs(function(obj, method, args) { var isFunc = _.isFunction(method); return _.map(obj, function(value) { var func = isFunc ? method : value[method]; return func == null ? func : func.apply(value, args); }); });
_.invoke 用于批量執(zhí)行方法,前面我們講了 restArgs 方法,雖然代碼很復雜,但目前實際上只應用了如下簡化的結構:
var restArgs = function(func) { return function() { return func.apply(this, arguments); }; };
也就是說 _.invoke 拋開閉包的概念之后等同于:
function(obj, method, args) { var isFunc = _.isFunction(method); return _.map(obj, function(value) { var func = isFunc ? method : value[method]; return func == null ? func : func.apply(value, args); }); }
其中 _.isFunction 是判斷是否為 function,接下來 _.map 回調,實際上我很納悶萬一傳入的 method 是 obj[i] 對象上沒有的方法怎么辦,按照 return 的結果如果沒有則返回 func 也就是 null,總覺得這樣返回缺少點什么。
_.pluck = function(obj, key) { return _.map(obj, _.property(key)); };
_.pluck 返回傳入 obj 的 key 的集合,或者說 key 的集合有點武斷,更具體點說是 obj 下第二層所包含 key 的值的集合,而第一層也就是 obj 可為 Object 或 Array,但 obj 中第二層必須是 Object。這是為什么呢?
_.map(obj, function(key) { return (function(obj) { return obj == null ? void 0 : obj[key]; })(key); })
在上述簡化的代碼中我們可以看出 return obj == null ? void 0 : obj[key]; 的值是 obj[key],所以第二層只能是 Object。
_.where = function(obj, attrs) { return _.filter(obj, _.matcher(attrs)); };
_.where 很有趣,代碼簡化之后是:
_.where = function(obj, attrs) { return _.filter(obj, (function(attrs) { attrs = _.extendOwn({}, attrs); return function(obj) { return _.isMatch(obj, attrs); })(attrs); }); };
_.filter 我們講過是獲取所有匹配值的集合,而回調中的 _.extendOwn 將 attrs 放入空對象 {} 中并 return,_.isMatch是個斷言用于判斷 obj 中是否存在 key-value。那么 _.where 就是 _.isMatch 和 _.filter 的加強版,它用于判斷一個大的對象數組中存在與傳入 attrs 相同的鍵值對,如果存在則返回匹配目標鍵值對所在的 Object,并且返回值是一個集合。
var list = [{author:"Shakespeare",title:"china"}, {author:"Shakespeare",year:1611,title:"china"}, {author:"Shakespeare",year:1611,title:"English"}, {year:1611,title:"china"}]; _.where(list, {author: "Shakespeare", year: 1611}); [{"author":"Shakespeare","year":1611,"title":"china"},{"author":"Shakespeare","year":1611,"title":"English"}]
這個方法在處理數據的時候特別有用。
_.findWhere = function(obj, attrs) { return _.find(obj, _.matcher(attrs)); };
_.findWhere,相當于 _.where()[0],即返回結果集合的第一個值,這么設定的目的和 _.find 與 _.filter 一樣,運算更快,遍歷到目標馬上停止遍歷。
_.max = function(obj, iteratee, context) { var result = -Infinity, lastComputed = -Infinity, value, computed; if (iteratee == null || (typeof iteratee == "number" && typeof obj[0] != "object") && obj != null) { obj = isArrayLike(obj) ? obj : _.values(obj); for (var i = 0, length = obj.length; i < length; i++) { value = obj[i]; if (value != null && value > result) { result = value; } } } else { iteratee = cb(iteratee, context); _.each(obj, function(v, index, list) { computed = iteratee(v, index, list); if (computed > lastComputed || computed === -Infinity && result === -Infinity) { result = v; lastComputed = computed; } }); } return result; };
_.max 用來查找 obj 對象數組中某一 key 的最大值的 Object,限定是 key-value 的 value 必須是 Number 類型。-Infinity 我更喜歡叫它負無窮,這里的 if true 第一個判斷可以忽略了,為什么不講了呢,因為作者要放棄 typeof iteratee == "number" && typeof obj[0] != "object" 這種情況,可見其他版本的 Underscore.js。如果忽略 typeof iteratee == "number" && typeof obj[0] != "object" 的情況則 _.max 傳參為一個數組,return 為數組中最大值。if false 則進行常規(guī)的 _.each 代碼很簡單這里不再講解。
_.min = function(obj, iteratee, context) { var result = Infinity, lastComputed = Infinity, value, computed; if (iteratee == null || (typeof iteratee == "number" && typeof obj[0] != "object") && obj != null) { obj = isArrayLike(obj) ? obj : _.values(obj); for (var i = 0, length = obj.length; i < length; i++) { value = obj[i]; if (value != null && value < result) { result = value; } } } else { iteratee = cb(iteratee, context); _.each(obj, function(v, index, list) { computed = iteratee(v, index, list); if (computed < lastComputed || computed === Infinity && result === Infinity) { result = v; lastComputed = computed; } }); } return result; };
_.min 真心不用講了,參考 _.max。
_.shuffle = function(obj) { return _.sample(obj, Infinity); };
_.shuffle 官網釋義是返回一個隨機亂序的 list 副本, 使用 Fisher-Yates shuffle 來進行隨機亂序.,Fisher-Yates shuffle 是什么鬼,我們這里看到 _.shuffle 這個函數用到了 _.sample,所以我們先講 _.sample。
_.sample = function(obj, n, guard) { if (n == null || guard) { if (!isArrayLike(obj)) obj = _.values(obj); return obj[_.random(obj.length - 1)]; } var sample = isArrayLike(obj) ? _.clone(obj) : _.values(obj); var length = getLength(sample); n = Math.max(Math.min(n, length), 0); var last = length - 1; for (var index = 0; index < n; index++) { var rand = _.random(index, last); var temp = sample[index]; sample[index] = sample[rand]; sample[rand] = temp; } return sample.slice(0, n); };
_.sample 是從一個 obj 中隨機返回值,并且返回值受限于 n 這個參數,如果沒有傳入 n 或者傳入了 guard = true 則執(zhí)行 if 語句,目的是將 obj 判斷處理之后返回單一值。這里覺得特雞肋有木有,也就是說 _.sample(obj,n,true) 和_.sample(obj) 是一回事。如果按照 _.sample(obj,n) 的邏輯執(zhí)行,依賴是老套路,處理 obj (Object 和 Array),然后 n = Math.max(Math.min(n, length), 0); 獲得合理的 n 值,前面我們講到了 Infinity 正無窮和 -Infinity 負無窮,這段代碼利用了 Infinity 的特性包裝了 _.shuffle函數,關鍵就是 Infinity 大于所有 Number 數字,即 Math.min(Infinity, Number) 等于 Number,好處就是讓人眼前一亮,哇,原來代碼還可以這樣寫,壞處就是當多帶帶使用 _.sample 函數的 n 大于處理之后的 obj 的長度時并不會報錯,而是默認執(zhí)行 n=sample.length,仁者見仁,智者見智吧。后面就是很套路的根據數組下標替換數組內容,當然數組下標是通過 _.random 隨機的,然后 slice 一刀切數組。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/86328.html
摘要:組件的選擇命令行工具首先我們需要一個命令行工具來方便的執(zhí)行命令,這里我們選擇組件,如果不喜歡使用且有能力的人完全可以通過組件自己封裝執(zhí)行命令函數。 對于一個成熟的項目而言,一定需要一個注釋文檔生成工具,我們有很多可選的開源項目,如jsdoc、yuidocjs 等等,擁有這些強大的工具我們完全可以勝任任何注釋方面的管理了么? 一個成熟的開發(fā)者都會知道不管怎么樣的項目都會在不同的開發(fā)條件下...
摘要:新出臺的則規(guī)定,包括六種原始類型和,還有一種,詳見數據類型和數據結構。用于返回一個由給定對象的所有可枚舉自身屬性的屬性名組成的數組,。接下來判斷數字進行相應的操作,其中有和兩個方法,詳見和。 一直想寫一篇這樣的文章,于是心動不如行動,這里選擇的是 Underscore.js 1.8.3 版本,源碼注釋加在一起1625行。 Underscore.js 1.8.3 http://unde...
摘要:第四個判斷如果是對象執(zhí)行返回一個斷言函數,用來判定傳入對象是否匹配指定鍵值屬性。都不匹配最后執(zhí)行,返回傳入的對象的屬性。設置的值并生成函數,等同于,使具有屬性且有值則返回,否則返回,這是一個判斷函數。 在第二小章節(jié)里面我按照源碼順序介紹幾個方法,源碼緊接著第一章繼續(xù): var builtinIteratee; builtinIteratee,內置的 Iteratee (迭代器)。...
摘要:接收三個參數分別為回調和,其中與是可選參數。官網釋義排序一個列表組成一個組,并且返回各組中的對象的數量的計數。類似,但是不是返回列表的值,而是返回在該組中值的數目。 繼續(xù)前面的內容,前文我們提到了很多方法的講解,其實到這里就已經差不多了,因為大部分代碼其實都是套路,一些基礎函數再靈活變化就可以組成很多實用的功能。 _.sortBy = function(obj, iteratee,...
摘要:用來構成和兩個函數,主要針對的是為了將函數調用模式更改為構造器調用和方法調用。通過函數設定時間為毫秒后執(zhí)行函數的回調函數,用以達到在規(guī)定時間毫秒時執(zhí)行函數的目的,并且規(guī)定時間內只執(zhí)行一次函數。 北京的雨已經斷斷續(xù)續(xù)下了好久,昏昏欲睡的躲在家里不愿意出門,火影忍者快要結束了,一拳超人第二季據說還要等好多年,勇者大冒險貌似斷更了,我又是在不喜歡海賊王的畫風,所以,我該看什么好呢。 va...
閱讀 2406·2021-10-09 09:44
閱讀 2139·2021-10-08 10:05
閱讀 3431·2021-07-26 23:38
閱讀 3008·2019-08-28 18:16
閱讀 820·2019-08-26 11:55
閱讀 1827·2019-08-23 18:29
閱讀 2042·2019-08-23 18:05
閱讀 1372·2019-08-23 17:02