每天一个Lodash源码解析
chunk()
方法介绍
_.chunk(array, [size=1])
将数组(array)拆分成多个 size 长度的区块,并将这些区块组成一个新数组。 如果array 无法被分割成全部等长的区块,那么最后剩余的元素将组成一个区块。
参数
- array (Array): 需要处理的数组
- [size=1] (number): 每个数组区块的长度
返回
- (Array): 返回一个包含拆分区块的新数组(注:相当于一个二维数组)。
例子
_.chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]
_.chunk(['a', 'b', 'c', 'd'], 3);
// => [['a', 'b', 'c'], ['d']]
自我实现
var chunk = function(arr, size) {
//初始化长度还有size的值
var l = arr.length
if (size == undefined) size = 1
//定义新数组和截取的始尾
var newA = []
var indexf = 0
var indexe = size
//处理特殊情况
if (size == 0) {
newA = []
return newA;
}
//循环截取数组
while (l > size) {
var a = arr.slice(indexf, indexe)
l = l - size
indexf = indexf + size
indexe = indexe + size
newA.push(a)
}
//未被截取到的情况
if (l > 0) {
indexf = indexe - size
indexe = arr.length
var a = arr.slice(indexf, indexe)
newA.push(a)
}
return newA;
}
源码分析
function chunk(array, size = 1) {//将size默认值设为1
//判断size的值是否小于0,如果小于0,则size值取0
size = Math.max(toInteger(size), 0)
//判断数组的值是否为null,如果为null,数组长度为0
const length = array == null ? 0 : array.length
//如果数组长度为0或者size<1,返回空数组
if (!length || size < 1) {
return []
}
let index = 0//截取数组坐标
let resIndex = 0//结果数组坐标
//用数组长度除以size并向上取整,得到分块个数
//新建一个长度为分块个数的新数组
const result = new Array(Math.ceil(length / size))
//循环截取数组
while (index < length) {
result[resIndex++] = slice(array, index, (index += size))
}
return result
}
代码对比
- 源码相对来说,减少了很多声明,并少了很多冗余的代码,且具有很好的可读性
- 对于数组接收到的值有很好的判断并处理
知识点补充
浮点数转化为浮点数
使用Math中的方法
- Math.floor():保留整数
- Math.ceil():向上取整
- Math.round():四舍五入
使用|
(位或运算符)将浮点数截断为整数。
console.log(23.9 | 0); // Result: 23;n为正,向下舍入
console.log(-23.9 | 0); //Result: -23;n为负,向上舍入
数组创建方法区别
使用new Array
创建的数组,具有length
属性,没有每个元素。
使用Array.from
创建的数组,具有length
属性,每个元素为undefined
,因此后续可以使用filter或者map等方法。
array.from
还可以转为类似数组的对象,...
扩展运算符不能。
//方法一 new Array
console.log(new Array(2))
//方法二 Array.from
console.log(Array.from({
length: 2
}))
//方法三
let arr = [1, 2]
console.log(arr)
//方法四
console.log([...arr])
运行结果
js中切割数组方法
slice()
返回一个索引和另一个索引之间的数据(不改变原数组),
slice(start,end)有两个参数(start必需,end选填),都是索引,返回值不包括end
splice()
用来添加或者删除数组的数据,只返回被删除的数据,类型为数组(改变原数组)
slice()
方法介绍
_.slice(array, [start=0], [end=array.length])
裁剪数组array,从 start 位置开始到end结束,但不包括 end 本身的位置。
Note: 这个方法用于代替Array#slice 来确保数组正确返回。
参数
- array (Array): 要裁剪数组。
- [start=0] (number): 开始位置。
- [end=array.length] (number): 结束位置。
返回
- (Array): 返回 数组array 裁剪部分的新数组。
PS:
- start 必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。
- end 可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。
自我实现
var slice = function(array, start, end) {
//定义数组
let a = []
//循环获取值
for (var i = start; i < end; i++) {
console.log(i)
a.push(array[i])
}
return a
}
源码分析
function slice(array, start, end) {
//判断数组是否为null,如果为null,length的值为0,否则为数组长度
let length = array == null ? 0 : array.length
//如果length为0,则返回空数组
if (!length) {
return []
}
//判断start和end的值是否为空
start = start == null ? 0 : start
end = end === undefined ? length : end
//如果start小于0,判断-start是否大于length
//如果-start大于length,则取0,否则取length+start
if (start < 0) {
start = -start > length ? 0 : (length + start)
}
//判断end是否大于length,如果是取length,否则取end
end = end > length ? length : end
//如果end小于0,end加等于length
if (end < 0) {
end += length
}
//设置返回新数组的长度
//如果start大于end,则取0,否则取end-start的结果,并确保其结果为正确的正整数
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
}
代码对比
- 相较于自我实现,对于传递过来的参数的的错误判断更为具体与正确
- 循环变量采用代码直接编写,没有调用方法,加快速度
知识点补充
>>>
移位运算
x >>> 0本质上就是保证x有意义(为数字类型),且为正整数,在有效的数组范围内(0 ~ 0xFFFFFFFF),且在无意义的情况下缺省值为0。
具体参考:https://segmentfault.com/a/1190000014613703
compact()
方法介绍
创建一个新数组,包含原数组中所有的非假值元素。例如false
, null
,0
," "
, undefined
, 和 NaN
都是被认为是“假值”。
参数
array
(Array): 待处理的数组
返回
- (Array): 返回过滤掉假值的新数组。
自我实现
var compact = function(array) {
//判断数组是否为空
if (array.length == 0) return []
var newaArray = []
//循环遍历判断值
for (let i = 0; i < array.length; i++) {
//获取数组中值的类型
var type = Object.prototype.toString.call(array[i])
if (type == '[object Null]' || type == '[object Undefined]') {//如果为空Null或者Undefined就跳过
continue;
} else if (type == '[object Number]') {//如果为0或者NaN就跳过
if (array[i] == 0 || isNaN(array[i])) continue;
else newaArray.push(array[i])
} else if (type == '[object Boolean]') {//如果为false就跳过
if (array[i] == false) continue;
else newaArray.push(array[i])
} else if (type == '[object String]') {//如果为""就跳过
if (array[i] == "") continue;
else newaArray.push(array[i])
} else {
newaArray.push(array[i])
}
}
return newaArray
}
源码分析
function compact(array) {
let resIndex = 0
const result = []
//如果array为null,则返回空数组
if (array == null) {
return result
}
遍历array数组,将数组中的每个元素转化为布尔值后判断是否为ture,false为虚假值,需要过滤
for (const value of array) {
if (value) {
result[resIndex++] = value
}
}
return result
}
代码对比
- 相较于自我实现,源码的代码简洁明了,通过转化为布尔类型省略了很多判断