一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
A modern JavaScript utility library delivering modularity, performance & extras.
lodash是一个一致性、模块化、高性能的JavaScript实用工具库
一、环境准备
-
lodash版本v4.0.0 -
通过
github1s网页可以 查看lodash - initial源码 -
调试测试用例可以
clone到本地
git clone https://github.com/lodash/lodash.git
cd axios
npm install
npm run test
二、结构分析
这是一张 initial 依赖引用路径图,按照功能划分,包含slice、initial。
三、函数研读
裁剪数组array,从 start 位置开始到end结束,但不包括 end 本身的位置
1. slice 模块
/**
* @since 3.0.0
* @category Array
* @param {Array} 要裁剪数组
* @param {number} 开始位置
* @param {number} 结束位置
* @returns {Array} 返回 数组`array` 裁剪部分的新数组
* @example
*
* var array = [1, 2, 3, 4]
*
* _.slice(array, 2)
* // => [3, 4]
*/
function slice(array, start, end) {
let length = array == null ? 0 : array.length;
if (!length) {
return [];
}
start = start == null ? 0 : start;
end = end === undefined ? length : end;
if (start < 0) {
start = -start > length ? 0 : length + start;
}
end = end > length ? length : end;
if (end < 0) {
end += length;
}
length = start > end ? 0 : (end - start) >>> 0;
start >>>= 0;
let index = -1;
const result = new Array(length);
while (++index < length) {
result[index] = array[index + start];
}
return result;
}
export default slice;
- 如果入参
array是null或者空数组则直接返[] - 如果开始位置
start未定义则默认为0,结束位置end未定义则默认为array的length值 - 如果开始位置
start小于0则为负索引,将被视为与array末尾位置的偏移量,需要注意的是如果偏移量大于array长度则默认为0,结束位置end同样处理 - 根据 start 与 end 计算返回区间,其中
>>> 0确保了 start 和 length 落在 js 双精度有效表达范围【0 ~ 0xFFFFFFFF】中,详情可以查看js 中表达式 >>> 0 浅析 - 最后使用
new Array(length)重新创建一个result数组并逐一赋值后返回
2. initial 模块
获取数组array中除了最后一个元素之外的所有元素
import slice from './slice.js'
/**
* @since 0.1.0
* @category Array
* @param {Array} array 要查询的数组
* @returns {Array} 返回截取后的数组array
* @example
*
* initial([1, 2, 3])
* // => [1, 2]
*/
function initial(array) {
const length = array == null ? 0 : array.length
return length ? slice(array, 0, -1) : []
}
export default initial
- 如果参数
array不为null并且有length属性,则认为其为Array类型,否则返回空数组 - 如果入参
array是Array类型,则进一步调用slice获取array中[0,array.length - 2]范围的内容,否则直接返回空数组
3.测试用例
import assert from 'assert';
import lodashStable from 'lodash';
import { falsey, stubArray, LARGE_ARRAY_SIZE } from './utils.js';
import initial from '../initial.js';
describe('initial', function() {
var array = [1, 2, 3];
it('should accept a falsey `array`', function() {
var expected = lodashStable.map(falsey, stubArray);
var actual = lodashStable.map(falsey, function(array, index) {
try {
return index ? initial(array) : initial();
} catch (e) {}
});
assert.deepStrictEqual(actual, expected);
});
it('should exclude last element', function() {
assert.deepStrictEqual(initial(array), [1, 2]);
});
it('should return an empty when querying empty arrays', function() {
assert.deepStrictEqual(initial([]), []);
});
it('should work as an iteratee for methods like `_.map`', function() {
var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
actual = lodashStable.map(array, initial);
assert.deepStrictEqual(actual, [[1, 2], [4, 5], [7, 8]]);
});
it('should work in a lazy sequence', function() {
var array = lodashStable.range(LARGE_ARRAY_SIZE),
values = [];
var actual = _(array).initial().filter(function(value) {
values.push(value);
return false;
})
.value();
assert.deepEqual(actual, []);
assert.deepEqual(values, initial(array));
values = [];
actual = _(array).filter(function(value) {
values.push(value);
return isEven(value);
})
.initial()
.value();
assert.deepEqual(actual, initial(lodashStable.filter(array, isEven)));
assert.deepEqual(values, array);
});
});
- 可以接受一个假值
array作为入参,其中stubArray = function() { return []; }, - 应该排除掉最后一项
- 入参为空数组时应该返回空数组
- 可以像
_.map一样对入参的数组元素每一项迭代 - 应该符合惰性运算要求
所谓像类 _.map 一样的方法作为数组迭代器入参,是指入参数组的每一项如果也是数组则其会作为入参再次被 head 递归调用,详情可以查看关于 map 的源码解析,这里不做额外说明。
的惰性运算可以参考lodash - first源码研读解析