首页 > 代码库 > lodash源码学习(10)

lodash源码学习(10)

_.delay(func, wait, [args])

延迟wait毫秒之后调用该函数,添加的参数为函数调用时的参数

//delay.jsvar 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.jsvar 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.jsvar 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.jsvar 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.jsvar baseSetData = http://www.mamicode.com/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/73343function 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 = http://www.mamicode.com/isBindKey ? undefined : getData(func);//得到func的元数据  var newData =http://www.mamicode.com/ [    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.jsvar 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.jsvar 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;//返回记忆方法}// 暴露MapCachememoize.Cache = MapCache;module.exports = memoize;

_.negate(predicate)

创建一个方法,得到判断方法的结果的否定,判断方法的this为生成的否定方法的this

//negate.jsvar 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.jsvar 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.jsvar 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.isArrayvar 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)