摘要:為情況下,直接返回執(zhí)行過程,對右側(cè)表達(dá)式求值。包裝執(zhí)行函數(shù)上下文創(chuàng)建迭代函數(shù),可選遍歷方向是的簡寫。遍歷整個(gè),返回匹配參數(shù)所列出的所有鍵值對的第一個(gè)值。傳遞一個(gè)數(shù)字表示從中返回個(gè)隨機(jī)元素。對集合每個(gè)元素調(diào)用函數(shù)后,得到。
// Internal function that returns an efficient (for current engines) version
// of the passed-in callback, to be repeatedly applied in other Underscore
// functions.
// 內(nèi)部復(fù)用函數(shù),用于改變函數(shù)上下文。
var optimizeCb = function(func, context, argCount) { //context為undefined情況下,直接返回func // void 0 // 執(zhí)行過程:1,對右側(cè)表達(dá)式求值。2.返回undefined // 為何這樣多此一舉:js中,undefined不是保留字,可以創(chuàng)建windows.undefined=anything.void返回undefined較安全。 // 用處:1返回undefined。2a標(biāo)簽不跳轉(zhuǎn)href=javascript:(void 0)3img空圖片src=javascript:(void 0) if (context === void 0) return func; //有傳入context情況下,將func上下文改為context switch (argCount == null ? 3 : argCount) { case 1: return function(value) { return func.call(context, value); }; // The 2-argument case is omitted because we’re not using it. case 3: return function(value, index, collection) { return func.call(context, value, index, collection); }; //_.reduce中使用 case 4: return function(accumulator, value, index, collection) { return func.call(context, accumulator, value, index, collection); }; } return function() { return func.apply(context, arguments); }; }; var builtinIteratee;
// An internal function to generate callbacks that can be applied to each
// element in a collection, returning the desired result — either identity,
// an arbitrary callback, a property matcher, or a property accessor.
// 內(nèi)部函數(shù),生成適用于集合每個(gè)元素的回調(diào)函數(shù)
// 傳入null等空值,得到等價(jià)函數(shù)
// 傳入function,得到綁定了上下文的函數(shù)
// 傳入對象,得到匹配函數(shù)
// 傳入其他,得到屬性訪問函數(shù)
var cb = function(value, context, argCount) { //??是何用意?? if (_.iteratee !== builtinIteratee) return _.iteratee(value, context); //返回null if (value == null) return _.identity; //如果是函數(shù),綁定函數(shù)上下文 if (_.isFunction(value)) return optimizeCb(value, context, argCount); //如果是對象,返回匹配函數(shù) if (_.isObject(value) && !_.isArray(value)) return _.matcher(value); //返回獲取屬性值函數(shù) return _.property(value); };
// External wrapper for our callback generator. Users may customize
// _.iteratee if they want additional predicate/iteratee shorthand styles.
// This abstraction hides the internal-only argCount argument.
// 外部函數(shù),返回cb函數(shù)結(jié)果
_.iteratee = builtinIteratee = function(value, context) { return cb(value, context, Infinity); };
// Some functions take a variable number of arguments, or a few expected
// arguments at the beginning and then a variable number of values to operate
// on. This helper accumulates all remaining arguments past the function’s
// argument length (or an explicit startIndex), into an array that becomes
// the last argument. Similar to ES6’s "rest parameter".
// 用于實(shí)參個(gè)數(shù)不定的函數(shù)的固定參數(shù)及剩余參數(shù)整理。
// example:_.invoke
// func.length=3,so startIndex=2,即從第三個(gè)參數(shù)開始,都存入rest變量中,并作為第三個(gè)參數(shù)傳入。第一二個(gè)參數(shù)不變。
// example:_.without
// func.length=2,so startIndex=1,即從第二個(gè)參數(shù)開始,都存入rest變量中,并作為第二個(gè)參數(shù)傳入第一個(gè)參數(shù)不變。
// example:_.union
// func.length=1,so startIndex=0,即將所有參數(shù)都傳入rest變量中,并作為第一個(gè)參數(shù)傳入。
// 最后一種情況,func形參個(gè)數(shù)大于3,不再使用call手動(dòng)傳入?yún)?shù)
// 而是利用apply的數(shù)組參數(shù)特性,將參數(shù)保存在數(shù)組中,再傳入函數(shù)。
var restArguments = function(func, startIndex) { console.log("func2") //func.length->形參個(gè)數(shù) startIndex = startIndex == null ? func.length - 1 : +startIndex; return function() { //func3 // arguments.length->實(shí)參個(gè)數(shù) // 個(gè)人理解:此處arguments指的是最貼近的這個(gè)閉包function在執(zhí)行時(shí)傳入的參數(shù),并不是func在執(zhí)行時(shí)傳入的參數(shù)個(gè)數(shù)。 console.log("func3") var length = Math.max(arguments.length - startIndex, 0), rest = Array(length), index = 0; for (; 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); }; };
// Invoke a method (with arguments) on every item in a collection.
// 在集合的每個(gè)元素上調(diào)用方法path,參數(shù)為arguments
// _.invoke([[3,4,5],[65,33,3]],"sort")函數(shù)運(yùn)行順序
// 在underscore.js加載編譯時(shí),restArgument被執(zhí)行,console func2。并返回匿名函數(shù)func3
// 在_.invoke()被執(zhí)行,即匿名函數(shù)func3被執(zhí)行,console func3。此時(shí)的arguments=[[[3,4,5],[65,33,3]],"sort"]。返回匿名函數(shù)func執(zhí)行的值
// 執(zhí)行func,console func。參數(shù)obj = arguments[0]=[[[3,4,5],[65,33,3]],path = arguemnts[1]="sort",args = rest = []
// console func4
// console func4
_.invoke = restArguments(function(obj, path, args) { //func console.log("func") var contextPath, func; if (_.isFunction(path)) { func = path; } else if (_.isArray(path)) { contextPath = path.slice(0, -1); path = path[path.length - 1]; } return _.map(obj, function(context) { //func4 console.log("func4") var method = func; if (!method) { if (contextPath && contextPath.length) { context = deepGet(context, contextPath); } if (context == null) return void 0; method = context[path]; } return method == null ? method : method.apply(context, args); }); });
// An internal function for creating a new object that inherits from another.
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; };
// 偏函數(shù)與柯里函數(shù)區(qū)別
// 偏函數(shù):傳入某些固定參數(shù)后,返回包含固定參數(shù),并可傳入其他參數(shù)的函數(shù)
// 柯里函數(shù):將n元參數(shù)的函數(shù)改變?yōu)閚次函數(shù),每次都只能傳入一個(gè)參數(shù)。
// 訪問屬性函數(shù)
var shallowProperty = function(key) { return function(obj) { return obj == null ? void 0 : obj[key]; }; };
//判斷是否存在自有屬性path
var has = function(obj, path) { return obj != null && hasOwnProperty.call(obj, path); }
//訪問對象的深度多級(jí)屬性 函數(shù)
var deepGet = function(obj, path) { var length = path.length; for (var i = 0; i < length; i++) { if (obj == null) return void 0; obj = obj[path[i]]; } return length ? obj : void 0; };
// Helper for collection methods to determine whether a collection
// should be iterated as an array or as an object.
// Related: http://people.mozilla.org/~jo...
// Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
// js 最大的精確整數(shù)值
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; var getLength = shallowProperty("length"); var isArrayLike = function(collection) { var length = getLength(collection); return typeof length == "number" && length >= 0 && length <= MAX_ARRAY_INDEX; };
// Collection Functions
// --------------------
// The cornerstone, an each implementation, aka forEach.
// Handles raw objects in addition to array-likes. Treats all
// sparse array-likes as if they were dense.
// each與map區(qū)別
// each中iteratee函數(shù)執(zhí)行結(jié)果不保存,返回obj本身
// map中iteratee函數(shù)執(zhí)行結(jié)果保存到數(shù)組results中,并返回。
_.each = _.forEach = function(obj, iteratee, context) { iteratee = optimizeCb(iteratee, context); var i, keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length; for (i = 0; i < length; i++) { var currentKey = keys ? keys[i] : i; iteratee(obj[currentKey], currentKey, obj); } return obj; };
// Return the results of applying the iteratee to each element.
_.map = _.collect = function(obj, iteratee, context) { //包裝執(zhí)行函數(shù)上下文 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; };
// Create a reducing function iterating left or right.
// 創(chuàng)建迭代函數(shù),可選遍歷方向
var createReduce = function(dir) { // Wrap code that reassigns argument variables in a separate function than // the one that accesses `arguments.length` to avoid a perf hit. (#1991) // perf hit是performance hit的簡寫。 // arguments的使用,會(huì)導(dǎo)致一些性能問題。如chrome nodejs的v8引擎在使用arguments會(huì)代碼優(yōu)化步驟被跳過。 var reducer = function(obj, iteratee, memo, initial) { //func2 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; }; // 此處返回func1函數(shù),作用域中包含initial變量,存放了arguments.length, // 用意就在于將arguments變量從reducer函數(shù)中分離出來, // 并在調(diào)用reducer函數(shù)時(shí),釋放argumenrs變量,避免性能問題。 return function(obj, iteratee, memo, context) { //func1 var initial = arguments.length >= 3; return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial); }; };
// Reduce builds up a single result from a list of values, aka inject,
// or foldl.
_.reduce = _.foldl = _.inject = createReduce(1);
// The right-associative version of reduce, also known as foldr.
_.reduceRight = _.foldr = createReduce(-1);
// Return the first value which passes a truth test. Aliased as detect.
// 返回第一個(gè)斷言問真的值
_.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]; };
// Return all the elements that pass a truth test.
// Aliased as select.
// 返回所有斷言為真的值組成的數(shù)組,中途不中斷
_.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; };
// Return all the elements for which a truth test fails.
// 返回所有斷言為假的值,
// 內(nèi)部直接調(diào)用filter
_.reject = function(obj, predicate, context) { return _.filter(obj, _.negate(cb(predicate)), context); };
// Determine whether all of the elements match a truth test.
// Aliased as all.
// 判斷是否所有斷言函數(shù)都為真,出現(xiàn)假立即返回
_.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; };
// Determine if at least one element in the object matches a truth test.
// Aliased as any.
// 檢測是否至少有一個(gè)值斷言為真,出現(xiàn)真立即返回
_.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; };
// Determine if the array or object contains a given item (using ===).
// Aliased as includes and include.
// 判斷從fromIndex索引開始,是否包含item
_.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; };
// Convenience version of a common use case of map: fetching a property.
// 萃取數(shù)組對象中某屬性值,返回一個(gè)數(shù)組
_.pluck = function(obj, key) { return _.map(obj, _.property(key)); };
// Convenience version of a common use case of filter: selecting only objects
// containing specific key:value pairs.
// 遍歷list中的每一個(gè)值,返回一個(gè)數(shù)組,這個(gè)數(shù)組里的元素包含 properties 所列出的鍵 - 值對。
_.where = function(obj, attrs) { return _.filter(obj, _.matcher(attrs)); };
// Convenience version of a common use case of find: getting the first object
// containing specific key:value pairs.
// 遍歷整個(gè)list,返回 matches(匹配) properties參數(shù)所列出的所有 鍵 - 值 對的第一個(gè)值。
_.findWhere = function(obj, attrs) { return _.find(obj, _.matcher(attrs)); };
// Return the maximum element (or element-based computation).
// 返回list中的最大值。如果傳遞iteratee參數(shù),iteratee將作為list中每個(gè)值的排序依據(jù)。
// 如果list為空,將返回-Infinity,所以你可能需要事先用isEmpty檢查 list 。
_.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; };
// Return the minimum element (or element-based computation).
// 返回list中的最小值。如果傳遞iteratee參數(shù),iteratee將作為list中每個(gè)值的排序依據(jù)。
// 如果list為空,將返回Infinity,所以你可能需要事先用isEmpty檢查 list 。
_.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; };
// Shuffle a collection.
_.shuffle = function(obj) { return _.sample(obj, Infinity); };
// Sample n random values from a collection using the modern version of the
// Fisher-Yates shuffle.
// If n is not specified, returns a single random element.
// The internal guard argument allows it to work with map.
// 從 list中產(chǎn)生一個(gè)隨機(jī)樣本。傳遞一個(gè)數(shù)字表示從list中返回n個(gè)隨機(jī)元素。否則將返回一個(gè)單一的隨機(jī)項(xiàng)。
_.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); //取一個(gè)符合0-length的合理值 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); };
// Sort the object"s values by a criterion produced by an iteratee.
// 返回一個(gè)(穩(wěn)定的)排序后的list拷貝副本。
// 如果傳遞iteratee參數(shù),iteratee將作為list中每個(gè)值的排序依據(jù)。
// 用來進(jìn)行排序迭代器也可以是屬性名稱的字符串(比如 length)。
_.sortBy = function(obj, iteratee, context) { var index = 0; iteratee = cb(iteratee, context); return _.pluck(_.map(obj, function(value, key, list) { return { value: value, index: index++, criteria: iteratee(value, key, list) }; }).sort(function(left, right) { var a = left.criteria; var b = right.criteria; if (a !== b) { if (a > b || a === void 0) return 1; if (a < b || b === void 0) return -1; } return left.index - right.index; }), "value"); };
// An internal function used for aggregate "group by" operations.
// 對集合每個(gè)元素調(diào)用iteratee函數(shù)后,得到key。
// 然后再根據(jù)behavior進(jìn)行分組
var group = function(behavior, partition) { return function(obj, iteratee, context) { var result = partition ? [ [], [] ] : {}; iteratee = cb(iteratee, context); _.each(obj, function(value, index) { var key = iteratee(value, index, obj); behavior(result, value, key); }); return result; }; };
// Groups the object"s values by a criterion. Pass either a string attribute
// to group by, or a function that returns the criterion.
// 把一個(gè)集合分組為多個(gè)集合,通過 iterator 返回的結(jié)果進(jìn)行分組.
// 如果 iterator 是一個(gè)字符串而不是函數(shù), 那么將使用 iterator 作為各元素的屬性名來對比進(jìn)行分組。
_.groupBy = group(function(result, value, key) { if (has(result, key)) result[key].push(value); else result[key] = [value]; });
// Indexes the object"s values by a criterion, similar to groupBy, but for
// when you know that your index values will be unique.
// 給定一個(gè)list,和 一個(gè)用來返回一個(gè)在列表中的每個(gè)元素鍵 的iterator 函數(shù)(或?qū)傩悦?返回一個(gè)每一項(xiàng)索引的對象。
// 和groupBy非常像,但是當(dāng)你知道你的鍵是唯一的時(shí)候可以使用indexBy 。
_.indexBy = group(function(result, value, key) { result[key] = value; });
// Counts instances of an object that group by a certain criterion. Pass
// either a string attribute to count by, or a function that returns the
// criterion.
// 排序一個(gè)列表組成多個(gè)組,并且返回各組中的對象的數(shù)量的計(jì)數(shù)。
// 類似groupBy,但是不是返回列表的值,而是返回在該組中值的數(shù)目。
_.countBy = group(function(result, value, key) { if (has(result, key)) result[key]++; else result[key] = 1; });
var reStrSymbol = /1|ud800-udbff|[ud800-udfff]/g;
// Safely create a real, live array from anything iterable.
_.toArray = function(obj) { if (!obj) return []; if (_.isArray(obj)) return slice.call(obj); if (_.isString(obj)) { // Keep surrogate pair characters together return obj.match(reStrSymbol); } if (isArrayLike(obj)) return _.map(obj, _.identity); return _.values(obj); };
// Return the number of elements in an object.
_.size = function(obj) { if (obj == null) return 0; return isArrayLike(obj) ? obj.length : _.keys(obj).length; };
// Split a collection into two arrays: one whose elements all satisfy the given
// predicate, and one whose elements all do not satisfy the predicate.
// 將 list 拆分為兩個(gè)數(shù)組:第一個(gè)數(shù)組其元素都滿足predicate迭代函數(shù), 而第二個(gè)的所有元素均不能滿足predicate迭代函數(shù)。
// predicate 通過 iteratee 進(jìn)行轉(zhuǎn)換,以簡化速記語法。
_.partition = group(function(result, value, pass) { result[pass ? 0 : 1].push(value); }, true);
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/103767.html
摘要:所以,剛開始,我從源碼比較短的包含注釋只有行開始學(xué)習(xí)起。一般,在客戶端瀏覽器環(huán)境中,即為,暴露在全局中。學(xué)習(xí)以后判斷直接使用看起來也優(yōu)雅一點(diǎn)滑稽臉。在的函數(shù)視線中,的作用執(zhí)行一個(gè)傳入函數(shù)次,并返回由每次執(zhí)行結(jié)果組成的數(shù)組。 前言 最近在社區(qū)瀏覽文章的時(shí)候,看到了一位大四學(xué)長在尋求前端工作中的面經(jīng),看完不得不佩服,掌握知識(shí)點(diǎn)真是全面,無論是前端后臺(tái)還是其他,都有涉獵。 在他寫的文章中,有...
摘要:它通過數(shù)據(jù)模型進(jìn)行鍵值綁定及事件處理,通過模型集合器提供一套豐富的用于枚舉功能,通過視圖來進(jìn)行事件處理及與現(xiàn)有的通過接口進(jìn)行交互。 本人兼職前端付費(fèi)技術(shù)顧問,如需幫助請加本人微信hawx1993或QQ345823102,非誠勿擾 1.為初學(xué)前端而不知道怎么做項(xiàng)目的你指導(dǎo) 2.指導(dǎo)并扎實(shí)你的JavaScript基礎(chǔ) 3.幫你準(zhǔn)備面試并提供相關(guān)指導(dǎo)性意見 4.為你的前端之路提供極具建設(shè)性的...
摘要:最近開始看源碼,并將源碼解讀放在了我的計(jì)劃中。將轉(zhuǎn)為數(shù)組同時(shí)去掉第一個(gè)元素之后便可以調(diào)用方法總結(jié)數(shù)組的擴(kuò)展方法就解讀到這里了,相關(guān)源碼可以參考這部分。放個(gè)預(yù)告,下一篇會(huì)暫緩下,講下相關(guān)的東西,敬請期待。 Why underscore 最近開始看 underscore.js 源碼,并將 underscore.js 源碼解讀 放在了我的 2016 計(jì)劃中。 閱讀一些著名框架類庫的源碼,就好...
摘要:新出臺(tái)的則規(guī)定,包括六種原始類型和,還有一種,詳見數(shù)據(jù)類型和數(shù)據(jù)結(jié)構(gòu)。用于返回一個(gè)由給定對象的所有可枚舉自身屬性的屬性名組成的數(shù)組,。接下來判斷數(shù)字進(jìn)行相應(yīng)的操作,其中有和兩個(gè)方法,詳見和。 一直想寫一篇這樣的文章,于是心動(dòng)不如行動(dòng),這里選擇的是 Underscore.js 1.8.3 版本,源碼注釋加在一起1625行。 Underscore.js 1.8.3 http://unde...
摘要:遍歷中的所有元素,按順序用遍歷輸出每個(gè)元素。如果傳遞了參數(shù),則把綁定到對象上。返回以方便鏈?zhǔn)秸{(diào)用。 each _.each(list, iteratee, [context])?Alias:?forEach?遍歷list中的所有元素,按順序用遍歷輸出每個(gè)元素。如果傳遞了context參數(shù),則把iteratee綁定到context對象上。每次調(diào)用iteratee都會(huì)傳遞三個(gè)參數(shù):(ele...
閱讀 2008·2019-08-29 16:27
閱讀 1379·2019-08-29 16:14
閱讀 3380·2019-08-29 14:18
閱讀 3463·2019-08-29 13:56
閱讀 1261·2019-08-29 11:13
閱讀 2131·2019-08-28 18:19
閱讀 3450·2019-08-27 10:57
閱讀 2287·2019-08-26 11:39