携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第31天,点击查看活动详情
前言
lodash里的内部方法createHybrid方法可以创建一个包装func的函数,用可选的this调用它。
在实现上,该方法借助了几个内部方法,我们先逐一了解各个内部方法的实现。
countHolders
countHolders方法可以获取数组中出现的占位符placeholder的数目。
参数说明:
- 参数1:数组类型,表示要检查的数组。
- 参数2:任意类型,表示要搜索的占位符。
countHolders方法实现上通过while遍历整个数组,当数组的某一项和占位符placeholder相等时,内部计数+1。
源码如下:
function countHolders(array, placeholder) {
var length = array.length,
result = 0;
while (length--) {
if (array[length] === placeholder) {
++result;
}
}
return result;
}
getHolder
getHolder方法可以获取参func的参数占位符值,该方法接收一个要检查的函数参数func,返回占位符的值。
源码如下:
function getHolder(func) {
var object = func;
return object.placeholder;
}
replaceHolders
replaceHolders方法可以用内部占位符替换“数组”中的所有“占位符”元素,同时返回其索引的数组。
源码如下:
var PLACEHOLDER = '__lodash_placeholder__';
function replaceHolders(array, placeholder) {
var index = -1,
length = array.length,
resIndex = 0,
result = [];
while (++index < length) {
var value = array[index];
if (value === placeholder || value === PLACEHOLDER) {
array[index] = PLACEHOLDER;
result[resIndex++] = index;
}
}
return result;
}
reorder
reorder方法主要是根据指定的索引对数组重新排序。
参数说明:
- 参数1:数组类型,表示要重新排序的数组。
- 参数2:数组类型,表示要排列的数组索引。
实现上借助copyArray方法和isIndex方法,通过while循环对数组进行遍历判断赋值,其中copyArray方法和isIndex方法在之前的篇章已经介绍过了,主要是复制数组和判断是否属于索引。
源码如下:
import copyArray from './_copyArray.js';
import isIndex from './_isIndex.js';
var nativeMin = Math.min;
function reorder(array, indexes) {
var arrLength = array.length,
length = nativeMin(indexes.length, arrLength),
oldArray = copyArray(array);
while (length--) {
var index = indexes[length];
array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
}
return array;
}
源码实现
在《
lodash里内部方法mergeData实现
》中我们介绍了composeArgs方法和composeArgsRight方法。
在《
lodash里的内部方法createBind
》中我们介绍了createCtor方法。
在《
lodash里的内部方法createRecurry
》中我们介绍了createRecurry方法。
通过代码判断以及各个方法的相互调用,createHybrid方法源码实现如下:
import composeArgs from './_composeArgs.js';
import composeArgsRight from './_composeArgsRight.js';
import countHolders from './_countHolders.js';
import createCtor from './_createCtor.js';
import createRecurry from './_createRecurry.js';
import getHolder from './_getHolder.js';
import reorder from './_reorder.js';
import replaceHolders from './_replaceHolders.js';
import root from './_root.js';
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;
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,
Ctor = isBindKey ? undefined : createCtor(func);
function wrapper() {
var length = arguments.length,
args = Array(length),
index = length;
while (index--) {
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();
}
if (isAry && ary < length) {
args.length = ary;
}
if (this && this !== root && this instanceof wrapper) {
fn = Ctor || createCtor(fn);
}
return fn.apply(thisBinding, args);
}
return wrapper;
}
小结
本篇章我们了解了createHybrid的实现过程,以及了解了其内部实现上调用的其他方法,同时也了解其他方法的实现。