• lodash源码学习(10)


    _.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;
  • 相关阅读:
    JavaSE基础day23 死锁、线程生命周期、枚举
    JavaSE基础day21 Thread类
    JavaSE基础day20 多线程3种实现方式
    JavaSE基础day22 线程安全问题、锁
    JavaSE基础day24 枚举常用方法、反射
    使用Blazor开发WinForm程序
    Blazor使用PDFObject预览pdf文件
    kubernetes的原理和使用
    docker的产生及应用
    JVM:方法区、堆
  • 原文地址:https://www.cnblogs.com/wandiao/p/7341835.html
Copyright © 2020-2023  润新知