lodash源碼學習(10)
阿新 • • 發佈:2017-08-11
返回 con ... eve ole func sarg 進行 pca
_.delay(func, wait, [args])
延遲wait毫秒之後調用該函數,添加的參數為函數調用時的參數
//delay.js var baseDelay = require(‘./_baseDelay‘),//baseDelay方法 baseRest = require(‘./_baseRest‘),//創建使用rest參數方法 toNumber = require(‘./toNumber‘);//轉化為數字 /** * * @param {Function} func 需要延遲執行的方法. * @param {number} wait 調用等待時間. * @param {...*} [args] 調用參數. * @returns {number} 返回time id. * @example * * _.delay(function(text) { * console.log(text); * }, 1000, ‘later‘); * // => Logs ‘later‘ after one second.*/ var delay = baseRest(function(func, wait, args) { return baseDelay(func, toNumber(wait) || 0, args); }); module.exports = delay;
這個方法依賴於baseDelay方法
//_baseDelay.js var FUNC_ERROR_TEXT = ‘Expected a function‘; /** * _.delay_.defer的基本實現 * * @private * @param {Function} func 需要延遲執行的函數. * @param {number} wait 調用等待時間. * @param {Array} args 調用參數. * @returns {number|Object} 返回time id.*/ function baseDelay(func, wait, args) { if (typeof func != ‘function‘) { throw new TypeError(FUNC_ERROR_TEXT); } return setTimeout(function() { func.apply(undefined, args); }, wait);//調用setTimeout方法,執行func並且傳入參數 } module.exports = baseDelay;
_.defer(func, [args])
延遲1毫秒之後調用該函數,添加的參數為函數調用時的參數
//defer.js var baseDelay = require(‘./_baseDelay‘), baseRest = require(‘./_baseRest‘); /** * * @param {Function} func 需要延遲執行的函數. * @param {...*} [args] 調用參數. * @returns {number} 返回timer id. * @example * * _.defer(function(text) { * console.log(text); * }, ‘deferred‘); * // => Logs ‘deferred‘ after one millisecond. */ var defer = baseRest(function(func, args) { return baseDelay(func, 1, args); }); module.exports = defer;
_.flip(func)
創建一個調用func的方法,並且將參數反向.
//flip.js var createWrap = require(‘./_createWrap‘); var WRAP_FLIP_FLAG = 512; /** * * @param {Function} func 需要將參數反向的方法. * @returns {Function} 返回處理之後的方法. * @example * * var flipped = _.flip(function() { * return _.toArray(arguments); * }); * * flipped(‘a‘, ‘b‘, ‘c‘, ‘d‘); * // => [‘d‘, ‘c‘, ‘b‘, ‘a‘] */ function flip(func) { return createWrap(func, WRAP_FLIP_FLAG); } module.exports = flip;
這個方法和很對方法一樣,依賴於createWrap方法和createHybrid方法,依然只分析對應部分
//_createWrap.js var baseSetData = require(‘./_baseSetData‘), createBind = require(‘./_createBind‘), createCurry = require(‘./_createCurry‘), createHybrid = require(‘./_createHybrid‘), createPartial = require(‘./_createPartial‘), getData = require(‘./_getData‘), mergeData = require(‘./_mergeData‘), setData = require(‘./_setData‘), setWrapToString = require(‘./_setWrapToString‘), toInteger = require(‘./toInteger‘); var FUNC_ERROR_TEXT = ‘Expected a function‘; //各種方法的位掩碼標識 var WRAP_BIND_FLAG = 1, WRAP_BIND_KEY_FLAG = 2, WRAP_CURRY_FLAG = 8, WRAP_CURRY_RIGHT_FLAG = 16, WRAP_PARTIAL_FLAG = 32, WRAP_PARTIAL_RIGHT_FLAG = 64; var nativeMax = Math.max;//原生最大值方法 /** * 創建一個函數,該函數可以創建或調用func用可選的this和部分應用的參數. * * @param {Function|string} func 需要包裝的函數. * @param {number} bitmask 位掩碼標識 * @param {*} [thisArg] func的this對象 * @param {Array} [partials] 應用的參數 * @param {Array} [holders] 占位符的索引 * @param {Array} [argPos] . * @param {number} [ary] . * @param {number} [arity] 可用參數數量. * @returns {Function} 返回包裝之後的函數. */ //lodash使用BitMask來進行各種方法的表示,BitMask使用方法可以看 http://geek.csdn.net/news/detail/73343 function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { var isBindKey = bitmask & WRAP_BIND_KEY_FLAG;//是否是bindKey方法(不是) if (!isBindKey && typeof func != ‘function‘) { throw new TypeError(FUNC_ERROR_TEXT); } var length = partials ? partials.length : 0;//應用的參數個數,為0 if (!length) { bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG);//清除WRAP_PARTIAL_FLAG和WRAP_PARTIAL_RIGHT_FLAG partials = holders = undefined;//部分參數和占位符索引都為undefined } ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0); arity = arity === undefined ? arity : toInteger(arity); length -= holders ? holders.length : 0; if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) {//是否是WRAP_PARTIAL_RIGHT_FLAG(不是,跳過) var partialsRight = partials, holdersRight = holders; partials = holders = undefined; } var data = isBindKey ? undefined : getData(func);//得到func的元數據 var newData = [ func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity ];//將所有參數賦值給newData if (data) { mergeData(newData, data);//合並data } func = newData[0]; bitmask = newData[1]; thisArg = newData[2]; partials = newData[3]; holders = newData[4]; arity = newData[9] = newData[9] === undefined ? (isBindKey ? 0 : func.length) : nativeMax(newData[9] - length, 0); if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) { bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG); } if (!bitmask || bitmask == WRAP_BIND_FLAG) { var result = createBind(func, bitmask, thisArg); } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) { result = createCurry(func, bitmask, arity); } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) { result = createPartial(func, bitmask, thisArg, partials); } else { result = createHybrid.apply(undefined, newData);//直接調用createHybrid方法 } var setter = data ? baseSetData : setData;//設置data的元數據(暫不分析) return setWrapToString(setter(result, newData), func, bitmask);//給包裝之後的方法添加元數據(用於優化),添加toStirng方法,並返回func(具體實現暫不分析) } module.exports = createWrap;
createHybrid方法
//_createHybrid.js var composeArgs = require(‘./_composeArgs‘), composeArgsRight = require(‘./_composeArgsRight‘), countHolders = require(‘./_countHolders‘), createCtor = require(‘./_createCtor‘), createRecurry = require(‘./_createRecurry‘), getHolder = require(‘./_getHolder‘), reorder = require(‘./_reorder‘), replaceHolders = require(‘./_replaceHolders‘), root = require(‘./_root‘); //位掩碼標識 var WRAP_BIND_FLAG = 1, WRAP_BIND_KEY_FLAG = 2, WRAP_CURRY_FLAG = 8, WRAP_CURRY_RIGHT_FLAG = 16, WRAP_ARY_FLAG = 128, WRAP_FLIP_FLAG = 512; /** * 創建一個包裝函數,調用func使用可選的thisArg,應用部分參數和柯裏化. * * @param {Function|string} func 需要包裝的方法. * @param {number} bitmask 位掩碼標識 * @param {*} [thisArg] . * @param {Array} [partials] 實現傳入的參數. * @param {Array} [holders] 占位符. * @param {Array} [partialsRight] . * @param {Array} [holdersRight] . * @param {Array} [argPos] . * @param {number} [ary] . * @param {number} [arity] 可用函數參數數量. * @returns {Function} 返回新的包裝函數. */ function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { var isAry = bitmask & WRAP_ARY_FLAG, isBind = bitmask & WRAP_BIND_FLAG, isBindKey = bitmask & WRAP_BIND_KEY_FLAG, isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG), isFlip = bitmask & WRAP_FLIP_FLAG,//是flip方法 Ctor = isBindKey ? undefined : createCtor(func); function wrapper() { var length = arguments.length,//參數個數 args = Array(length),//保存所有參數 index = length;//參數數組索引 while (index--) {//遍歷參數,將所有參數存入args args[index] = arguments[index]; } if (isCurried) { var placeholder = getHolder(wrapper), holdersCount = countHolders(args, placeholder); } if (partials) { args = composeArgs(args, partials, holders, isCurried); } if (partialsRight) { args = composeArgsRight(args, partialsRight, holdersRight, isCurried); } length -= holdersCount; if (isCurried && length < arity) { var newHolders = replaceHolders(args, placeholder); return createRecurry( func, bitmask, createHybrid, wrapper.placeholder, thisArg, args, newHolders, argPos, ary, arity - length ); } var thisBinding = isBind ? thisArg : this, fn = isBindKey ? thisBinding[func] : func; length = args.length;//參數長度 if (argPos) { args = reorder(args, argPos); } else if (isFlip && length > 1) { args.reverse();//直接將args反向,就這麽簡單。。。。 } if (isAry && ary < length) { args.length = ary; } if (this && this !== root && this instanceof wrapper) { fn = Ctor || createCtor(fn); } return fn.apply(thisBinding, args);//調用fn,並且傳入args } return wrapper;//返回包裝方法 } module.exports = createHybrid;
_.memoize(func, [resolver])
創建一個可以記錄func返回結果的方法,默認緩存key的值為func的第一個參數.如果傳入了resolver,key為resolver的執行結果,resolver的參數為傳入func的參數
* 如果需要修改記錄結果,可以使用memoized.cache.set(key,value)
//memorize.js var MapCache = require(‘./_MapCache‘);//map緩存對象 /** Error message constants. */ var FUNC_ERROR_TEXT = ‘Expected a function‘; /** * * * @param {Function} func 需要記錄結果的方法. * @param {Function} [resolver] 緩存key的生成方法. * @returns {Function} 生成記憶方法. * @example * * var object = { ‘a‘: 1, ‘b‘: 2 }; * var other = { ‘c‘: 3, ‘d‘: 4 }; * * var values = _.memoize(_.values); * values(object); * // => [1, 2] * * values(other); * // => [3, 4] * * object.a = 2; * values(object); * // => [1, 2] * * // Modify the result cache. * values.cache.set(object, [‘a‘, ‘b‘]); * values(object); * // => [‘a‘, ‘b‘] * * // Replace `_.memoize.Cache`. * _.memoize.Cache = WeakMap; */ function memoize(func, resolver) { if (typeof func != ‘function‘ || (resolver != null && typeof resolver != ‘function‘)) { throw new TypeError(FUNC_ERROR_TEXT); } var memoized = function() { var args = arguments,//參數對象 key = resolver ? resolver.apply(this, args) : args[0],//緩存key值 cache = memoized.cache;//記憶函數的緩存對象 if (cache.has(key)) {//如果緩存中含有key return cache.get(key);//返回對應的value } var result = func.apply(this, args);//沒有值,調用func得到結果 memoized.cache = cache.set(key, result) || cache;//將結果存入緩存中 return result;//返回結果 }; memoized.cache = new (memoize.Cache || MapCache);//初始化記憶方法的緩存。 return memoized;//返回記憶方法 } // 暴露MapCache memoize.Cache = MapCache; module.exports = memoize;
_.negate(predicate)
創建一個方法,得到判斷方法的結果的否定,判斷方法的this為生成的否定方法的this
//negate.js var FUNC_ERROR_TEXT = ‘Expected a function‘; /** * * @param {Function} predicate 需要否定的判斷方法. * @returns {Function} 返回新的否定方法. * @example * * function isEven(n) { * return n % 2 == 0; * } * * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); * // => [1, 3, 5] */ function negate(predicate) { if (typeof predicate != ‘function‘) { throw new TypeError(FUNC_ERROR_TEXT); } return function() { var args = arguments;//參數對象 switch (args.length) {//參數小於3個,通過call調用判斷方法,並返回否定的結果 case 0: return !predicate.call(this); case 1: return !predicate.call(this, args[0]); case 2: return !predicate.call(this, args[0], args[1]); case 3: return !predicate.call(this, args[0], args[1], args[2]); } return !predicate.apply(this, args);//參數大於3個,通過apply調用判斷方法,並返回否定的結果 }; } module.exports = negate;
_.once(func)
創建一個方法,限制func只能調用一次
//once.js var before = require(‘./before‘);//before方法,見源碼學習(7) /** * * * @param {Function} func 需要限制調用的方法. * @returns {Function} 返回限制方法. * @example * * var initialize = _.once(createApplication); * initialize(); * initialize(); * // => `createApplication` is invoked once */ function once(func) { return before(2, func);//調用before方法,調用次數小於2 } module.exports = once;
_.overArgs(func, [transforms=[_.identity]])
//overArgs.js var apply = require(‘./_apply‘),//同Function.apply arrayMap = require(‘./_arrayMap‘),//同Array.map baseFlatten = require(‘./_baseFlatten‘),//數組扁平化方法,見源碼學習(1) baseIteratee = require(‘./_baseIteratee‘),//遍歷器封裝 baseRest = require(‘./_baseRest‘),//創建具有rest參數的方法 baseUnary = require(‘./_baseUnary‘),//創建只有一個參數的方法 castRest = require(‘./_castRest‘),//同baseRest isArray = require(‘./isArray‘);//同Array.isArray var nativeMin = Math.min;//原生求最小值方法 /** * 創建一個方法,調用func並且將調用的參數進行對應的轉化. * * @param {Function} func 需要保裝的方法. * @param {...(Function|Function[])} [transforms=[_.identity]] 參數對應的轉換方法. * @returns {Function} 返回新的方法. * @example * * function doubled(n) { * return n * 2; * } * * function square(n) { * return n * n; * } * * var func = _.overArgs(function(x, y) { * return [x, y]; * }, [square, doubled]); * * func(9, 3); * // => [81, 6] * * func(10, 5); * // => [100, 10] */ var overArgs = castRest(function(func, transforms) { //如果轉換器只有一個且為數組,遍歷這個數組,並且進行封裝 //否則將傳入的轉換器扁平化,遍歷數組,並且進行封裝封裝 transforms = (transforms.length == 1 && isArray(transforms[0])) ? arrayMap(transforms[0], baseUnary(baseIteratee)) : arrayMap(baseFlatten(transforms, 1), baseUnary(baseIteratee)); var funcsLength = transforms.length;//轉換器的長度 return baseRest(function(args) { var index = -1,//參數索引 length = nativeMin(args.length, funcsLength);//需要轉化的個數 while (++index < length) {//循環,轉化對應的參數 args[index] = transforms[index].call(this, args[index]); } return apply(func, this, args);//調用func }); }); module.exports = overArgs;
lodash源碼學習(10)