lodash里的内部方法createRecurry

624 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第31天,点击查看活动详情

前言

lodash里的内部方法createRecurry,主要是创建一个函数,该函数包装参数func以继续柯里化。

参数说明:

  • 参数1:函数类型,表示要包装的函数。
  • 参数2:数字类型,表示位掩码标志。
  • 参数3:函数类型,表示用于创建func包装器的函数。
  • 参数4:任意类型,表示占位符值
  • 参数5:任意类型,表示参数func的this绑定。
  • 参数6:数组类型,表示提供给前面参数的参数数组。
  • 参数7:数组类型,表示参数6partials的占位符索引。
  • 参数8:数组类型,表示新函数的参数位置。
  • 参数9:数字类型,表示参数func的算术上限。
  • 参数10:数字类型,表示表示参数func的数量。

该方法实现借助isLaziable、setData、setWrapToString方法,我们先了解各自方法的实现。关于setData的实现可以在《 lodash里内部方法getData和setData的实现 》中了解,而setWrapToString方法主要是设置参数wrapper的“toString”方法以模拟“reference”的源。

isLaziable

isLaziable方法可以检查参数func是否有惰性对应项。

该方法实现借助了LazyWrapper、getData、getFuncName、lodash等内部方法。其中getData方法在《 lodash里内部方法getData和setData的实现 》中已经了解其实现。

LazyWrapper

LazyWrapper方法可以创建一个延迟包装器对象,该对象包装参数value以启用延迟计算。

实现上借助baseCreate方法和baseLodash方法。其中,baseCreate方法在 《 lodash里的内部方法createBind 》中已经了解到。而baseLodash表示一个包装器继承自函数。

function baseLodash() {}

LazyWrapper源码如下:

import baseCreate from './_baseCreate.js';
import baseLodash from './_baseLodash.js';

var MAX_ARRAY_LENGTH = 4294967295;

function LazyWrapper(value) {
  this.__wrapped__ = value;
  this.__actions__ = [];
  this.__dir__ = 1;
  this.__filtered__ = false;
  this.__iteratees__ = [];
  this.__takeCount__ = MAX_ARRAY_LENGTH;
  this.__views__ = [];
}

LazyWrapper.prototype = baseCreate(baseLodash.prototype);
LazyWrapper.prototype.constructor = LazyWrapper;

isLaziable源码实现

import LazyWrapper from './_LazyWrapper.js';
import getData from './_getData.js';
import getFuncName from './_getFuncName.js';
import lodash from './wrapperLodash.js';

function isLaziable(func) {
  var funcName = getFuncName(func),
      other = lodash[funcName];

  if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
    return false;
  }
  if (func === other) {
    return true;
  }
  var data = getData(other);
  return !!data && func === data[0];
}

createRecurry源码实现

import isLaziable from './_isLaziable.js';
import setData from './_setData.js';
import setWrapToString from './_setWrapToString.js';

var WRAP_BIND_FLAG = 1,
    WRAP_BIND_KEY_FLAG = 2,
    WRAP_CURRY_BOUND_FLAG = 4,
    WRAP_CURRY_FLAG = 8,
    WRAP_PARTIAL_FLAG = 32,
    WRAP_PARTIAL_RIGHT_FLAG = 64;

function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
  var isCurry = bitmask & WRAP_CURRY_FLAG,
      newHolders = isCurry ? holders : undefined,
      newHoldersRight = isCurry ? undefined : holders,
      newPartials = isCurry ? partials : undefined,
      newPartialsRight = isCurry ? undefined : partials;

  bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG);
  bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG);

  if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) {
    bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG);
  }
  var newData = [
    func, bitmask, thisArg, newPartials, newHolders, newPartialsRight,
    newHoldersRight, argPos, ary, arity
  ];

  var result = wrapFunc.apply(undefined, newData);
  if (isLaziable(func)) {
    setData(result, newData);
  }
  result.placeholder = placeholder;
  return setWrapToString(result, func, bitmask);
}

小结

本篇章我们了解到createRecurry方法的实现,内部调用封装的isLaziable、setData、setWrapToString方法,实现了参数func的柯里化。