前置

chunk 函数内部借助其他函数实现,所以从其他函数开始,chunk 在最后。

你可能需要一些 JavaScript 基础知识才能看懂一些没有注释的细节。

isObject

判断是否为 Object 类型

/**
* Checks if `value` is the
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* isObject({})
* // => true
*
* isObject([1, 2, 3])
* // => true
*
* isObject(Function)
* // => true
*
* isObject(null)
* // => false
*/
function isObject(value) {
const type = typeof value
// 将 function 作为 Object 类型
return value != null && (type === 'object' || type === 'function')
} export default isObject

getTag

getTag 获取给定值的 toStringTag

Symbol.toStringTag 是一个内置 symbol,它通常作为对象的属性键使用,对应的属性值应该为字符串类型,这个字符串用来表示该对象的自定义类型标签,通常只有内置的 Object.prototype.toString() 方法会去读取这个标签并把它包含在自己的返回值里。

许多内置的 JavaScript 对象类型即便没有 toStringTag 属性,也能被 toString() 方法识别并返回特定的类型标签,比如:

Object.prototype.toString.call('foo');     // "[object String]"
Object.prototype.toString.call([1, 2]); // "[object Array]"
Object.prototype.toString.call(3); // "[object Number]"
Object.prototype.toString.call(true); // "[object Boolean]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call(null); // "[object Null]"
// ... and more

另外一些对象类型则不然,toString() 方法能识别它们是因为引擎为它们设置好了 toStringTag 标签:

Object.prototype.toString.call(new Map());       // "[object Map]"
Object.prototype.toString.call(function* () {}); // "[object GeneratorFunction]"
Object.prototype.toString.call(Promise.resolve()); // "[object Promise]"
// ... and more

对于你自己创建的类,toString() 找不到 toStringTag 属性时只好返回默认的 Object 标签:

class ValidatorClass {}

Object.prototype.toString.call(new ValidatorClass()); // "[object Object]"

加上 toStringTag 属性,你的类也会有自定义的类型标签了:

class ValidatorClass {
get [Symbol.toStringTag]() {
return "Validator";
}
} Object.prototype.toString.call(new ValidatorClass()); // "[object Validator]"
const toString = Object.prototype.toString

/**
* Gets the `toStringTag` of `value`.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the `toStringTag`.
*/
function getTag(value) { // 处理 value 能够转化为 null 的值
if (value == null) {
return value === undefined ? '[object Undefined]' : '[object Null]'
}
return toString.call(value)
} export default getTag

isSymbol

_.isSymbol(value)

检查 value 是否是原始 Symbol 或者对象

import getTag from './.internal/getTag.js'

/**
* Checks if `value` is classified as a `Symbol` primitive or object.
*
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
* @example
*
* isSymbol(Symbol.iterator)
* // => true
*
* isSymbol('abc')
* // => false
*/
function isSymbol(value) {
// typeof 比 Object.prototype.toString 效率高
const type = typeof value
return type == 'symbol' || (type === 'object' && value != null && getTag(value) == '[object Symbol]')
} export default isSymbol

toNumber

_.toNumber(value)

转换 value 为一个数字

import isObject from './isObject.js'
import isSymbol from './isSymbol.js' /** Used as references for various `Number` constants. */
const NAN = 0 / 0 /** Used to match leading and trailing whitespace. */
const reTrim = /^\s+|\s+$/g /** Used to detect bad signed hexadecimal string values. */
// 用于检测错误的有符号十六进制字符串值
const reIsBadHex = /^[-+]0x[0-9a-f]+$/i /** Used to detect binary string values. */
// 二进制。
const reIsBinary = /^0b[01]+$/i /** Used to detect octal string values. */
// 八进制
const reIsOctal = /^0o[0-7]+$/i /** Built-in method references without a dependency on `root`. */
// 不依赖于 root 的内置方法引用
// 防止全局作用域下的parseInt被用户替换
const freeParseInt = parseInt /**
* Converts `value` to a number.
*
* @since 4.0.0
* @category Lang
* @param {*} value The value to process.
* @returns {number} Returns the number.
* @see isInteger, toInteger, isNumber
* @example
*
* toNumber(3.2)
* // => 3.2
*
* toNumber(Number.MIN_VALUE)
* // => 5e-324
*
* toNumber(Infinity)
* // => Infinity
*
* toNumber('3.2')
* // => 3.2
*/
function toNumber(value) {
if (typeof value === 'number') {
return value
}
if (isSymbol(value)) {
return NAN // Number 的引用
} // Object.prototype.valueOf() 方法返回指定对象的原始值
// 默认情况下,valueOf方法由Object后面的每个对象继承。
// 每个内置的核心对象都会覆盖此方法以返回适当的值。
// 如果对象没有原始值,则valueOf将返回对象本身。
if (isObject(value)) {
// value 没有 valueOf 函数或者 valueOf 函数返回一个对象,
// 将 other 转换成 string 类型,留待后面处理。
const other = typeof value.valueOf === 'function' ? value.valueOf() : value
value = isObject(other) ? `${other}` : other
}
if (typeof value !== 'string') {
return value === 0 ? value : +value
}
// @example
// const a = function() {}
// console.log(a.valueOf());
// -> [Function: a]
// console.log(typeof a.valueOf());
// -> function // @example
// const a = {}
// console.log(a.valueOf();
// -> {} // 16进制返回NAN
// 10进制数(+)确保返回值是数值类型
value = value.replace(reTrim, '') // 用''替换掉字符串中符合reTrim的项
const isBinary = reIsBinary.test(value) // 二进制
return (isBinary || reIsOctal.test(value)) // 二进制或八进制
? freeParseInt(value.slice(2), isBinary ? 2 : 8) // 删除字符串前两位并解析为十进制的整数
: (reIsBadHex.test(value) ? NAN : +value) // 十六进制字符串值返回 NAN,否则返回十进制(+)
} export default toNumber

toFinite

_.toFinite(value)

转换 value 为一个有限数字

import toNumber from './toNumber.js'

/** Used as references for various `Number` constants. */
const INFINITY = 1 / 0 // 无穷
const MAX_INTEGER = 1.7976931348623157e+308 // 最大整数 /**
* Converts `value` to a finite number.
*
* @since 4.12.0
* @category Lang
* @param {*} value The value to convert.
* @returns {number} Returns the converted number.
* @example
*
* toFinite(3.2)
* // => 3.2
*
* toFinite(Number.MIN_VALUE)
* // => 5e-324
*
* toFinite(Infinity)
* // => 1.7976931348623157e+308
*
* toFinite('3.2')
* // => 3.2
*/
function toFinite(value) {
// undefined & null -> 0
if (!value) {
return value === 0 ? value : 0
}
value = toNumber(value)
// 正负无穷取正负最大值
if (value === INFINITY || value === -INFINITY) {
const sign = (value < 0 ? -1 : 1)
return sign * MAX_INTEGER
}
return value === value ? value : 0
} export default toFinite

toInteger

_.toInteger(value)

转换 value 为一个整数

import toFinite from './toFinite.js'

/**
* Converts `value` to an integer.
*
* **Note:** This method is loosely based on
* [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
*
* @since 4.0.0
* @category Lang
* @param {*} value The value to convert.
* @returns {number} Returns the converted integer.
* @see isInteger, isNumber, toNumber
* @example
*
* toInteger(3.2)
* // => 3
*
* toInteger(Number.MIN_VALUE)
* // => 0
*
* toInteger(Infinity)
* // => 1.7976931348623157e+308
*
* toInteger('3.2')
* // => 3
*/
function toInteger(value) {
const result = toFinite(value) // result 为小数时,则 remainder 不为 0
const remainder = result % 1 // 余数 // 抹掉小数位
return remainder ? result - remainder : result
} export default toInteger

chunk

_.chunk(array, [size=1])

将数组拆分成多个 size 长度的区块,并将这些区块组成一个新数组。 如果array 无法被分割成全部等长的区块,那么最后剩余的元素将组成一个区块。

import slice from './slice.js'
import toInteger from './toInteger.js' /**
* @since 3.0.0
* @category Array
* @param {Array} array The array to process.
* @param {number} [size=1] The length of each chunk
* @returns {Array} Returns the new array of chunks.
* @example
*
* chunk(['a', 'b', 'c', 'd'], 2)
* // => [['a', 'b'], ['c', 'd']]
*
* chunk(['a', 'b', 'c', 'd'], 3)
* // => [['a', 'b', 'c'], ['d']]
*/
function chunk(array, size = 1) {
// 令 size >= 0
size = Math.max(toInteger(size), 0) const length = array == null ? 0 : array.length
if (!length || size < 1) {
return []
} // 构建新数组
let index = 0
let resIndex = 0
const result = new Array(Math.ceil(length / size))
while (index < length) {
result[resIndex++] = slice(array, index, (index += size))
} return result
} export default chunk

参考资料:MDN

硬刚 lodash 源码之路,_.chunk的更多相关文章

  1. 硬刚 lodash 源码之路,compact & concat

    前置 本篇随笔包含 _.compact 和 _.concat 及其依赖的工具函数. 你可能需要一些 JavaScript 基础知识才能看懂一些没有注释的细节. compact _.compact(ar ...

  2. lodash源码分析之chunk的尺与刀

    以不正义开始的事情,必须用罪恶使它巩固. --莎士比亚<麦克白> 最近很多事似乎印证了这句话,一句谎言最后要用一百句谎言来圆谎. 本文为读 lodash 源码的第二篇,后续文章会更新到这个 ...

  3. lodash源码分析之compact中的遍历

    小时候, 乡愁是一枚小小的邮票, 我在这头, 母亲在那头. 长大后,乡愁是一张窄窄的船票, 我在这头, 新娘在那头. 后来啊, 乡愁是一方矮矮的坟墓, 我在外头, 母亲在里头. 而现在, 乡愁是一湾浅 ...

  4. lodash源码分析之NaN不是NaN

    暗恋之纯粹,在于不求结果,完全把自己锁闭在一个单向的关系里面. --梁文道<暗恋到偷窥> 本文为读 lodash 源码的第五篇,后续文章会更新到这个仓库中,欢迎 star:pocket-l ...

  5. 惰性求值——lodash源码解读

    前言 lodash受欢迎的一个原因,是其优异的计算性能.而其性能能有这么突出的表现,很大部分就来源于其使用的算法--惰性求值. 本文将讲述lodash源码中,惰性求值的原理和实现. 一.惰性求值的原理 ...

  6. 读lodash源码之从slice看稀疏数组与密集数组

    卑鄙是卑鄙者的通行证,高尚是高尚者的墓志铭. --北岛<回答> 看北岛就是从这两句诗开始的,高尚者已死,只剩卑鄙者在世间横行. 本文为读 lodash 源码的第一篇,后续文章会更新到这个仓 ...

  7. lodash源码分析之Hash缓存

    在那小小的梦的暖阁,我为你收藏起整个季节的烟雨. --洛夫<灵河> 本文为读 lodash 源码的第四篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash gitbo ...

  8. lodash源码分析之自减的两种形式

    这个世界需要一个特定的恶人,可以供人们指名道姓,千夫所指:"全都怪你". --村上春树<当我谈跑步时我谈些什么> 本文为读 lodash 源码的第六篇,后续文章会更新到 ...

  9. lodash源码分析之List缓存

    昨日我沿着河岸/漫步到/芦苇弯腰喝水的地方 顺便请烟囱/在天空为我写一封长长的信 潦是潦草了些/而我的心意/则明亮亦如你窗前的烛光/稍有暧昧之处/势所难免/因为风的缘故 --洛夫<因为风的缘故& ...

随机推荐

  1. Java实现 LeetCode 107 二叉树的层次遍历 II(二)

    107. 二叉树的层次遍历 II 给定一个二叉树,返回其节点值自底向上的层次遍历. (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 例如: 给定二叉树 [3,9,20,null,null, ...

  2. Java实现 LeetCode 27 移除元素

    27. 移除元素 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额 ...

  3. 从源码研究如何不重启Springboot项目实现redis配置动态切换

    上一篇Websocket的续篇暂时还没有动手写,这篇算是插播吧.今天讲讲不重启项目动态切换redis服务. 背景 多个项目或微服务场景下,各个项目都需要配置redis数据源.但是,每当运维搞事时(修改 ...

  4. 什么!你想要封装好的ajax

    ajax作为前端开发领域一个必不可少的内容,也是灵魂所在,今天就ajax的封装给大家做一个分析, 如果没有猜错的话现在基本上用原生去写ajax的意见不多了,这是肯定的 ,为什么这么说,jq的ajax大 ...

  5. MIT6.S081/6.828 实验1:Lab Unix Utilities

    Mit6.828/6.S081 fall 2019的Lab1是Unix utilities,主要内容为利用xv6的系统调用实现sleep.pingpong.primes.find和xargs等工具.本 ...

  6. mysql基础之-mysql数据控制语言DCL(七)

    0x01 mysql中的权限分布 mysql中的用户信息都存储在系统数据库mysql的user表中 查询语句:select host,user,password from mysql.user; 创建 ...

  7. Python的数据的基本类型

    基本数据类型 int整数 str 字符串   一般不存放大量的数据 bool  布尔值,用来判断. True,False    list  列表.存放大量数据,[]表示,里面可以放各种数据类型     ...

  8. Redis学习笔记(二十一) 事务

    文章开始啰嗦两句,写到这里共21篇关于redis的琐碎知识,没有过多的写编程过程中redis的应用,着重写的是redis命令.客户端.服务器以及生产环境搭建用到的主从.哨兵.集群实现原理,如果你真的能 ...

  9. VS Code WebApi系列——3、发布

    上两篇已经实现了WebApi及基于jwt的Token设置,那么功能做完了,该发布WebApi了.为什么要对发布进行一下说明呢,因为是基于vscode和.netcore的发布,所以可能会遇到莫名奇妙的问 ...

  10. cb28a_c++_STL_算法_查找算法_(1)find_find_if

    cb28a_c++_STL_算法_查找算法_(1)find_find_iffind() //线性查找,比较慢.pos1 = find(ilist.begin(), ilist.end(), 5);fi ...