摘要:第四個判斷如果是對象執(zhí)行返回一個斷言函數(shù),用來判定傳入對象是否匹配指定鍵值屬性。都不匹配最后執(zhí)行,返回傳入的對象的屬性。設(shè)置的值并生成函數(shù),等同于,使具有屬性且有值則返回,否則返回,這是一個判斷函數(shù)。
在第二小章節(jié)里面我按照源碼順序介紹幾個方法,源碼緊接著第一章繼續(xù):
var builtinIteratee;
builtinIteratee,內(nèi)置的 Iteratee (迭代器)。
var cb = function(value, context, argCount) { if (_.iteratee !== builtinIteratee) return _.iteratee(value, context); if (value == null) return _.identity; if (_.isFunction(value)) return optimizeCb(value, context, argCount); if (_.isObject(value)) return _.matcher(value); return _.property(value); };
cb 函數(shù)接受三個參數(shù),陸續(xù)四個判斷,第一個判斷 _.iteratee,根據(jù) JAVASCRIPT 的上下文,首先 builtinIteratee 為 undefined,然 cb 函數(shù)內(nèi) builtinIteratee 為 undefined,接下來就是 _.iteratee = builtinIteratee 里面的 cb 函數(shù),so...接著第二個判斷傳入?yún)?shù)是否為空值,如果是則返回 _.identity 函數(shù),即當(dāng)前傳入值。第三個判斷傳入值是方法則執(zhí)行 optimizeCb 函數(shù)。第四個判斷如果是對象執(zhí)行返回一個斷言函數(shù),用來判定傳入對象是否匹配attrs指定鍵/值屬性。都不匹配最后執(zhí)行 _.property,返回傳入的對象的 key 屬性。
_.iteratee = builtinIteratee = function(value, context) { return cb(value, context, Infinity); };
_.iteratee 這個函數(shù)一般認(rèn)為是一個迭代器,這里是作者的主觀寫法,因為從意義上講, cb 函數(shù)和 _.iteratee 函數(shù)很相似,甚至說只要稍加改動 cb 完全可以替換掉 _.iteratee,作者用 _.iteratee 包裝 cb 并提供外部訪問,雖然實際工作中我們運(yùn)用 _.iteratee 函數(shù)并不常見,但如果用的好絕對是一利器,由 underscore.js 源碼內(nèi)部隨處可見的 cb(),就知道這一函數(shù)的作用之大。在 underscore 中 return cb() 傳入了第三個參數(shù) Infinity,意為參數(shù)類型為 Infinity 當(dāng)執(zhí)行第三個 cb 函數(shù)的 if 判斷,執(zhí)行 return optimizeCb(); 時就會發(fā)揮其作用,Infinity 類型也蠻有意思,有興趣的同學(xué)可以參考 Infinity、POSITIVE_INFINITY 和 NEGATIVE_INFINITY。
var restArgs = function(func, startIndex) { startIndex = startIndex == null ? func.length - 1 : +startIndex; return function() { var length = Math.max(arguments.length - startIndex, 0); var rest = Array(length); for (var index = 0; index < length; index++) { rest[index] = arguments[index + startIndex]; } switch (startIndex) { case 0: return func.call(this, rest); case 1: return func.call(this, arguments[0], rest); case 2: return func.call(this, arguments[0], arguments[1], rest); } var args = Array(startIndex + 1); for (index = 0; index < startIndex; index++) { args[index] = arguments[index]; } args[startIndex] = rest; return func.apply(this, args); }; };
restArgs(其余的參數(shù)),什么意思呢,我們看它傳入了一個 function 和 一個 Number 類型的 startIndex 標(biāo)識,首先處理的是 startIndex。三元運(yùn)算判斷 startIndex 是否存在,是則為 +startIndex,否則為 func.length - 1 即傳入 function 中的傳入形參的數(shù)量減一,舉個例子如:
var aFunction = function(a,b,c){}; function(a){ console.log(a.length) //3 }
這么做的目的是什么呢,我們都知道在一個 Array 中數(shù)組排序是從 0 開始,所以就不難理解 func.length - 1,但是 +startIndex 又是為什么呢,答案是同樣是考慮數(shù)組排序是從 0 開始。其實在源碼中 restArgs 這個內(nèi)部函數(shù)作者還并沒有用到過 startIndex 這個參數(shù),如果需要使用那么它的意義在于 return function 的時候處理 function 中的一部分參數(shù),我們現(xiàn)在假設(shè)使用了 startIndex 參數(shù),如果 startIndex >2 即拋去 arguments[startIndex + 1] 作為傳入?yún)?shù)的一步限定,然后將 arguments[arguments.length - startIndex + 1] ~ arguments[arguments.length] 封裝數(shù)組作為 arguments[startIndex] 傳入,當(dāng)然這過程中需要將 arguments[arguments.length - startIndex + 1] ~ arguments[arguments.length] 從 arguments 刪除,所以源碼中運(yùn)用了多個 Array 用于這一過程其目的就是重組 arguments。而當(dāng) 0
前面說到作者并沒有使用 startIndex 這個參數(shù),那么沒有 startIndex 是什么情況呢,startIndex = func.length - 1 就是說設(shè)定 Array 的長度即 arguments 的長度,我們可以看到作者對 restArgs 這個函數(shù)很重視,并且好像一直在優(yōu)化它,作者想要做什么也不得而知,畢竟拋開 startIndex 的話:
var restArgs = function(func) { startIndex = func.length - 1; return function() { var rest = Array(1); rest[0] = arguments[startIndex]; var args = Array(arguments.length); for (index = 0; index < startIndex; index++) { args[index] = arguments[index]; } args[startIndex] = rest; return func.apply(this, args); }; };
等同于:
var restArgs = function(func) { return function() { return func.apply(this, arguments); }; };
作者將5行代碼擴(kuò)展到21行,其實就是為了一個 startIndex 而已。
var baseCreate = function(prototype) { if (!_.isObject(prototype)) return {}; if (nativeCreate) return nativeCreate(prototype); Ctor.prototype = prototype; var result = new Ctor; Ctor.prototype = null; return result; };
baseCreate 用于創(chuàng)建一個干凈且只存在具有想要其具有 prototype 的函數(shù),第一個判斷是否具有 prototype 參數(shù),第二個判斷運(yùn)用 Object.create 創(chuàng)建,余下則是自己運(yùn)用 Ctor 這個空函數(shù)創(chuàng)建,沒什么可細(xì)說的。
var property = function(key) { return function(obj) { return obj == null ? void 0 : obj[key]; }; };
property 用于獲取 obj 的 key 值,通過 property() 設(shè)置 key ,重點是設(shè)置兩個字,有 key 則以沒有則創(chuàng)建之。
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
設(shè)置 一個最大值 MAX_ARRAY_INDEX,Math.pow(2, 53) - 1 意為2的53次冪等于9007199254740991,Math 的相關(guān)函數(shù)參考 Math,其實我一直覺得 MAX_ARRAY_INDEX 并不用設(shè)置這么大的值,Math.pow(2, 16) 就足以。
var getLength = property("length");
設(shè)置 obj 的 key 值并生成函數(shù),等同于:
var getLength = function(obj) { return obj == null ? void 0 : obj["length"]; };
var isArrayLike = function(collection) { var length = getLength(collection); return typeof length == "number" && length >= 0 && length <= MAX_ARRAY_INDEX; };
isArrayLike,使 Obj 具有 length 屬性且有值則返回 true,否則返回 false,這是一個判斷函數(shù)。
_.each = _.forEach = function(obj, iteratee, context) { iteratee = optimizeCb(iteratee, context); var i, length; if (isArrayLike(obj)) { for (i = 0, length = obj.length; i < length; i++) { iteratee(obj[i], i, obj); } } else { var keys = _.keys(obj); for (i = 0, length = keys.length; i < length; i++) { iteratee(obj[keys[i]], keys[i], obj); } } return obj; };
我一直以為 JAVASCRIPT 最精華的就是回調(diào)的執(zhí)行方式,雖然互聯(lián)網(wǎng)上一些文章總在說回調(diào)毀了一切,人云亦云等等,但是回調(diào)支撐起了所有的框架,而且回調(diào)很優(yōu)雅用的好可以很舒服,回調(diào)不是毀了一切只是因為某些人不恰當(dāng)?shù)脑O(shè)置回調(diào)毀了他自己的代碼。在 _.forEach 中 iteratee 即回調(diào)函數(shù),其中運(yùn)用了 optimizeCb 優(yōu)化回調(diào),然后是一個常規(guī)判斷,這里為什么用 isArrayLike(obj) 而不是 isArray(obj) 來判斷是不是數(shù)組呢,留下一個思考問題。
_.map = _.collect = function(obj, iteratee, context) { iteratee = cb(iteratee, context); var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length, results = Array(length); for (var index = 0; index < length; index++) { var currentKey = keys ? keys[index] : index; results[index] = iteratee(obj[currentKey], currentKey, obj); } return results; };
封裝 map 函數(shù),沒什么好說的,參考 Map、Map.prototype、WeakMap 用于知識儲備,至于作者的 _.map 更多的是根據(jù)一定的條件遍歷 obj 中的元素,與 _.forEach 的更大區(qū)別是 _.forEach 不會對傳入的 obj 做改動直接 return obj,而 _.map 會 return results,return results 是每個 iteratee 回調(diào)的集合。
var createReduce = function(dir) { var reducer = function(obj, iteratee, memo, initial) { var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length, index = dir > 0 ? 0 : length - 1; if (!initial) { memo = obj[keys ? keys[index] : index]; index += dir; } for (; index >= 0 && index < length; index += dir) { var currentKey = keys ? keys[index] : index; memo = iteratee(memo, obj[currentKey], currentKey, obj); } return memo; }; return function(obj, iteratee, memo, context) { var initial = arguments.length >= 3; return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial); }; };
createReduce,創(chuàng)建 reduce。關(guān)于 reduce 的介紹可見 reduce 方法 (Array) (JavaScript):https://msdn.microsoft.com/library/ff679975(v=vs.94).aspx 和 array-reduce,作者這里的 reduce 肯定不是這樣,但既然命名為 createReduce,想來也脫不了太多關(guān)系。函數(shù)中 reducer 首先定義 keys,其值為 obj 的 key 集合或者 false,后面幾個語句里都有對于 keys 的三元運(yùn)算,目的就是排除 obj 不為 Object 的可能性。接下來判斷傳入 initial,如果傳入 initial 為 false 則默認(rèn) memo 值為 keys[keys.length-1] || 0,之后是 for 循環(huán)遍歷回調(diào),并返回最后一個回調(diào)值。跳出 reducer 函數(shù) return function 的恰恰是引用 reducer 函數(shù)的外部接口,于是所有一切都連貫上了,包括 initial 的定義是 arguments 長度大于等于3等等。
我們再重新過一遍代碼,在最外部 return 的時候判斷 initial,實際上就是再確定是否傳入了 memo 和 context,當(dāng)然最主要的就是 memo,以此來確定在內(nèi)部 reducer 的時候是否具有初始值。在這里我覺得作者應(yīng)該對 memo 進(jìn)行類型判斷的,如果是 Number 或者 String 還說的過去,但是如果傳入 memo 是 Object 就有點說不過去了,會出錯的。比如:
_.reduce([1, 2, 3], function(memo, num){ return memo + num; }); 6 _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 1); 7 _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, "1"); "1123" _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, []); "123" _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, [1,2]); "1,2123" _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, {a:1}); "[object Object]123"
_.reduce = _.foldl = _.inject = createReduce(1);
這里就是用 createReduce 包裝好的 _.reduce,不解釋。
_.reduceRight = _.foldr = createReduce(-1);
這里就是用 createReduce 包裝好的 _.reduceRight,與 _.reduce 計算順序相反即從右面向左面開始。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/86314.html
摘要:組件的選擇命令行工具首先我們需要一個命令行工具來方便的執(zhí)行命令,這里我們選擇組件,如果不喜歡使用且有能力的人完全可以通過組件自己封裝執(zhí)行命令函數(shù)。 對于一個成熟的項目而言,一定需要一個注釋文檔生成工具,我們有很多可選的開源項目,如jsdoc、yuidocjs 等等,擁有這些強(qiáng)大的工具我們完全可以勝任任何注釋方面的管理了么? 一個成熟的開發(fā)者都會知道不管怎么樣的項目都會在不同的開發(fā)條件下...
摘要:新出臺的則規(guī)定,包括六種原始類型和,還有一種,詳見數(shù)據(jù)類型和數(shù)據(jù)結(jié)構(gòu)。用于返回一個由給定對象的所有可枚舉自身屬性的屬性名組成的數(shù)組,。接下來判斷數(shù)字進(jìn)行相應(yīng)的操作,其中有和兩個方法,詳見和。 一直想寫一篇這樣的文章,于是心動不如行動,這里選擇的是 Underscore.js 1.8.3 版本,源碼注釋加在一起1625行。 Underscore.js 1.8.3 http://unde...
摘要:用來構(gòu)成和兩個函數(shù),主要針對的是為了將函數(shù)調(diào)用模式更改為構(gòu)造器調(diào)用和方法調(diào)用。通過函數(shù)設(shè)定時間為毫秒后執(zhí)行函數(shù)的回調(diào)函數(shù),用以達(dá)到在規(guī)定時間毫秒時執(zhí)行函數(shù)的目的,并且規(guī)定時間內(nèi)只執(zhí)行一次函數(shù)。 北京的雨已經(jīng)斷斷續(xù)續(xù)下了好久,昏昏欲睡的躲在家里不愿意出門,火影忍者快要結(jié)束了,一拳超人第二季據(jù)說還要等好多年,勇者大冒險貌似斷更了,我又是在不喜歡海賊王的畫風(fēng),所以,我該看什么好呢。 va...
摘要:接收三個參數(shù)分別為回調(diào)和,其中與是可選參數(shù)。官網(wǎng)釋義排序一個列表組成一個組,并且返回各組中的對象的數(shù)量的計數(shù)。類似,但是不是返回列表的值,而是返回在該組中值的數(shù)目。 繼續(xù)前面的內(nèi)容,前文我們提到了很多方法的講解,其實到這里就已經(jīng)差不多了,因為大部分代碼其實都是套路,一些基礎(chǔ)函數(shù)再靈活變化就可以組成很多實用的功能。 _.sortBy = function(obj, iteratee,...
摘要:傳入值進(jìn)行判斷以此決定函數(shù),將三個參數(shù)包括回調(diào)傳入中其中回調(diào)函數(shù)充當(dāng)?shù)鬟M(jìn)行真值檢測,最后。是從一個中隨機(jī)返回值,并且返回值受限于這個參數(shù),如果沒有傳入或者傳入了則執(zhí)行語句,目的是將判斷處理之后返回單一值。 今天繼續(xù)上次的內(nèi)容,之前我們講到了 reduce 的用法,其實我覺得用法倒是其次的關(guān)鍵是作者實現(xiàn) reduce 過程中所靈活用到的函數(shù)處理方法,我們只要有心稍加總覺完全可以拿來主...
閱讀 2636·2021-11-18 10:07
閱讀 1089·2021-08-03 14:04
閱讀 731·2019-08-30 13:08
閱讀 2586·2019-08-29 15:33
閱讀 1099·2019-08-29 14:07
閱讀 2997·2019-08-29 14:04
閱讀 1447·2019-08-29 11:19
閱讀 1152·2019-08-29 10:59