createHybridWrapper.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. var arrayCopy = require('./arrayCopy'),
  2. composeArgs = require('./composeArgs'),
  3. composeArgsRight = require('./composeArgsRight'),
  4. createCtorWrapper = require('./createCtorWrapper'),
  5. isLaziable = require('./isLaziable'),
  6. reorder = require('./reorder'),
  7. replaceHolders = require('./replaceHolders'),
  8. setData = require('./setData');
  9. /** Used to compose bitmasks for wrapper metadata. */
  10. var BIND_FLAG = 1,
  11. BIND_KEY_FLAG = 2,
  12. CURRY_BOUND_FLAG = 4,
  13. CURRY_FLAG = 8,
  14. CURRY_RIGHT_FLAG = 16,
  15. PARTIAL_FLAG = 32,
  16. PARTIAL_RIGHT_FLAG = 64,
  17. ARY_FLAG = 128;
  18. /* Native method references for those with the same name as other `lodash` methods. */
  19. var nativeMax = Math.max;
  20. /**
  21. * Creates a function that wraps `func` and invokes it with optional `this`
  22. * binding of, partial application, and currying.
  23. *
  24. * @private
  25. * @param {Function|string} func The function or method name to reference.
  26. * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
  27. * @param {*} [thisArg] The `this` binding of `func`.
  28. * @param {Array} [partials] The arguments to prepend to those provided to the new function.
  29. * @param {Array} [holders] The `partials` placeholder indexes.
  30. * @param {Array} [partialsRight] The arguments to append to those provided to the new function.
  31. * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
  32. * @param {Array} [argPos] The argument positions of the new function.
  33. * @param {number} [ary] The arity cap of `func`.
  34. * @param {number} [arity] The arity of `func`.
  35. * @returns {Function} Returns the new wrapped function.
  36. */
  37. function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
  38. var isAry = bitmask & ARY_FLAG,
  39. isBind = bitmask & BIND_FLAG,
  40. isBindKey = bitmask & BIND_KEY_FLAG,
  41. isCurry = bitmask & CURRY_FLAG,
  42. isCurryBound = bitmask & CURRY_BOUND_FLAG,
  43. isCurryRight = bitmask & CURRY_RIGHT_FLAG,
  44. Ctor = isBindKey ? undefined : createCtorWrapper(func);
  45. function wrapper() {
  46. // Avoid `arguments` object use disqualifying optimizations by
  47. // converting it to an array before providing it to other functions.
  48. var length = arguments.length,
  49. index = length,
  50. args = Array(length);
  51. while (index--) {
  52. args[index] = arguments[index];
  53. }
  54. if (partials) {
  55. args = composeArgs(args, partials, holders);
  56. }
  57. if (partialsRight) {
  58. args = composeArgsRight(args, partialsRight, holdersRight);
  59. }
  60. if (isCurry || isCurryRight) {
  61. var placeholder = wrapper.placeholder,
  62. argsHolders = replaceHolders(args, placeholder);
  63. length -= argsHolders.length;
  64. if (length < arity) {
  65. var newArgPos = argPos ? arrayCopy(argPos) : undefined,
  66. newArity = nativeMax(arity - length, 0),
  67. newsHolders = isCurry ? argsHolders : undefined,
  68. newHoldersRight = isCurry ? undefined : argsHolders,
  69. newPartials = isCurry ? args : undefined,
  70. newPartialsRight = isCurry ? undefined : args;
  71. bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
  72. bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
  73. if (!isCurryBound) {
  74. bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
  75. }
  76. var newData = [func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity],
  77. result = createHybridWrapper.apply(undefined, newData);
  78. if (isLaziable(func)) {
  79. setData(result, newData);
  80. }
  81. result.placeholder = placeholder;
  82. return result;
  83. }
  84. }
  85. var thisBinding = isBind ? thisArg : this,
  86. fn = isBindKey ? thisBinding[func] : func;
  87. if (argPos) {
  88. args = reorder(args, argPos);
  89. }
  90. if (isAry && ary < args.length) {
  91. args.length = ary;
  92. }
  93. if (this && this !== global && this instanceof wrapper) {
  94. fn = Ctor || createCtorWrapper(func);
  95. }
  96. return fn.apply(thisBinding, args);
  97. }
  98. return wrapper;
  99. }
  100. module.exports = createHybridWrapper;