【源码学习】Radash(一)Typed 类型判断
Radash
Radash,这个新兴的工具库,以其现代化的设计和对 TypeScript 的原生支持,迅速吸引了开发者的注意。虽然 Radash 是新项目,最近刷很多文章都有推荐,作为 Lodash 的替代,它在 GitHub 上的 star 涨幅很快 ,这表明它是一个有前途的工具库。大家都说好用,而且支持TS,那么我们就来一探究竟吧!
Radash 的特点包括:
- 零依赖:Radash 不依赖于任何第三方库,使得项目更加轻量级
- TypeScript 友好:Radash 完全使用 TypeScript 编写,提供了准确的类型定义
- 现代化功能:Radash 去除了 Lodash 中一些过时的函数,并引入了许多新的实用功能
- 易于理解和维护:Radash 的源代码易于理解,对新手友好
最主要是看着简单,很容易学习 ~ 现在分的类型也不多, VueUse的坑还没完,这又开新坑了…… 哈哈,先干再说
源码确实很简单,很容易上手和学习,写这样一个系列也不会有厌烦情绪了。
配合着官方例子,加了点自己的解读,若有错误还请批评指出,谢谢(抱拳)!~
Typed
typed.ts
类型判断,也作为整个库的工具方法会被其他文件频繁调用 ~ 在项目中封装这些类型判断可高度借鉴
isArray
- 基本用法
传入一个值并获取一个布尔值,告诉您该值是否是数组。
1import { isArray } from 'radash'
2
3isArray('hello') // => false
4isArray(['hello']) // => true
5
- 源码解析
1// 当一个变量 isArray 被赋值为 Array.isArray 时
2// 它实际上引用的是 Array 构造函数 ( class Array 上的静态方法 )
3export const isArray = Array.isArray
4// Array.hasOwnProperty('isArray') -> true
5
isDate
确定值是否为日期
- 基本用法
确定值是否为日期。不检查输入日期是否有效,仅检查它是 Javascript 日期类型。
1import { isDate } from 'radash'
2
3isDate(new Date()) // => true
4isDate(12) // => false
5isDate('hello') // => false
6
- 源码分析
1export const isDate = (value: any): value is Date => {
2 // 使用 Object.prototype.toString.call(value) 方法
3 // 来获取给定值(value)的类型字符串
4 // 然后检查该字符串是否等于'[object Date]'
5 return Object.prototype.toString.call(value) === '[object Date]'
6}
7
由于这段代码依赖于
Object.prototype.toString
方法,因此不能在非 ES6 环境中运行。在非 ES6 环境中,你可以使用其他方法来实现相同的功能,例如使用typeof value === 'object'
来检查值是否是一个对象,然后使用value instanceof Date
来检查值是否是 Date 类的实例
isEmpty
判断一个值是否为空
- 基本用法
这个函数主要用于处理复杂类型的值,包括布尔值、null、undefined、数字、日期、函数、符号等
1import { isEmpty } from 'radash'
2
3isEmpty([]) // => true
4isEmpty('') // => true
5
6isEmpty('hello') // => false
7isEmpty(['hello']) // => false
8
- 源码解析
1export const isEmpty = (value: any) => {
2 // 首先,检查value是否为 布尔值 亦或是 null 或 undefined
3 // 如果是,则返回true
4 if (value === true || value === false) return true
5 if (value === null || value === undefined) return true
6
7 // 然后,检查value是否为数字
8 // 若是,判断 value是否等于0 返回该布尔值
9 if (isNumber(value)) return value === 0
10
11 // 检查value是否为日期,如果是 value.getTime() 会转换为时间戳
12 // 时间戳若有效的,isNaN 为 false,否则为 true
13 if (isDate(value)) return isNaN(value.getTime())
14
15 // 检查value是否为函数,如果是,则返回false
16 if (isFunction(value)) return false
17
18 // 检查value是否为 Symbol,如果是,则返回false
19 if (isSymbol(value)) return false
20
21 // 获取value的长度或大小(如果有的话),并检查其是否为0
22 // 为0,则说明是空数组,返回true,否则为 false
23 const length = (value as any).length
24 if (isNumber(length)) return length === 0
25 // 同上,这里针对 Map、Set
26 const size = (value as any).size
27 if (isNumber(size)) return size === 0
28
29 const keys = Object.keys(value).length
30 return keys === 0
31}
32
这段代码使用了类型断言(as any),这可能会导致运行时错误,因为类型断言会跳过类型检查。建议在使用时尽可能地进行类型检查和验证。
这段代码没有处理循环引用的情况,如果 value 是一个对象,并且对象之间存在循环引用,那么 Object.keys(value)可能会导致栈溢出错误。
isEqual
确定两个值是否相等
- 基本用法
给定两个值,如果它们相等则返回 true。( 值比较)主要目的是实现一个通用且高效的比较器,可以用来比较任何类型的数据,包括对象、数组、字符串、数字、布尔值等。
1import { isEqual } from 'radash'
2
3isEqual(null, null) // => true
4isEqual([], []) // => true
5
6isEqual('hello', 'world') // => false
7isEqual(22, 'abc') // => false
8
- 源码解析
1export const isEqual = <TType>(x: TType, y: TType): boolean => {
2 // Object.is方法来检查x和y是否是同一个对象
3 if (Object.is(x, y)) return true
4
5 // 分别检查x和y是否是Date对象。如果是,则比较它们的日期时间戳是否相等
6 if (x instanceof Date && y instanceof Date) {
7 return x.getTime() === y.getTime()
8 }
9
10 // 检查x和y是否是正则对象。如果是,则比较它们的内部表示是否相等。
11 if (x instanceof RegExp && y instanceof RegExp) {
12 return x.toString() === y.toString()
13 }
14
15 // 检查x和y是否不是对象或者null。如果是,则返回false
16 if (typeof x !== 'object' || x === null || typeof y !== 'object' || y === null) {
17 return false
18 }
19
20 // 这里稍微复杂些
21 // 如果x和y是对象,则获取它们自己的属性键数组,并遍历这些属性键
22 const keysX = Reflect.ownKeys(x as unknown as object) as (keyof typeof x)[]
23 const keysY = Reflect.ownKeys(y as unknown as object)
24
25 // 检查y是否具有相同的属性键,并且对应的属性值是否与x相等。
26 if (keysX.length !== keysY.length) return false
27 for (let i = 0; i < keysX.length; i++) {
28 if (!Reflect.has(y as unknown as object, keysX[i])) return false
29 if (!isEqual(x[keysX[i]], y[keysX[i]])) return false
30 }
31 // 如果所有属性都相等,则返回true。
32 return true
33}
34
isFloat
判断一个值是否为浮点数
- 基本用法
传入一个值并获取一个布尔值,告诉您该值是否为浮点型。
1import { isFloat } from 'radash'
2
3isFloat(12.233) // => true
4isFloat(12) // => false
5isFloat('hello') // => false
6
- 源码解析
1export const isFloat = (value: any): value is number => {
2 // isNumber 函数会检查传入的值是否为 Number 类型,包括整数和浮点数
3 // 使用逻辑运算符 % 检查 value 是否为整数
4 return isNumber(value) && value % 1 !== 0
5 // 如果 value 是浮点数,它将不会被整除
6}
7
isFunction
判断一个值是否是一个函数
- 基本用法
1import { isFunction } from 'radash'
2
3isFunction('hello') // => false
4isFunction(['hello']) // => false
5isFunction(() => 'hello') // => true
6
- 源码解析
1export const isFunction = (value: any): value is Function => {
2 // 通过检查value是否为null或undefined,
3 // 然后检查value是否有constructor属性,
4 // 并判断其call和apply方法是否为函数
5 return !!(value && value.constructor && value.call && value.apply)
6}
7
虽然这个函数在大多数情况下能够正确判断传入的值是否为函数,但在某些特殊情况(如 null 或 undefined)中,它会返回 true,这可能不是预期的行为。在处理这些特殊情况时,可能需要额外的检查。
isInt
判断一个值是否为 int
- 基本用法
这个函数可以用于检查变量是否为有效的整数,从而避免在代码中出现非预期的整数行为。
例如,在处理数字字符串或从用户输入中获取数据时,可以使用 isInt 函数来确保输入的是一个整数。
1import { isInt } from 'radash'
2
3isInt(12) // => true
4isInt(12.233) // => false
5isInt('hello') // => false
6
- 源码解析
1export const isInt = (value: any): value is number => {
2 // 1. 使用isNumber函数检查value是否为数字(包括整数和浮点数)
3 // 2. 使用逻辑运算符&&连接isNumber(value)和value % 1 === 0
4 // 3. 如果value是数字且是整数,则返回true,否则返回false
5 return isNumber(value) && value % 1 === 0
6}
7
- isInt 函数不能检查负数和 0 是否为整数,因为它只检查正整数。要检查一个值是否为负整数,可以使用 value < 0 && value % 1 !== 0。
- isInt 函数不能处理非数字类型的值,例如 null、undefined、string、object 等。在处理这些值时,需要先检查它们是否为数字,然后再使用 isInt 函数。
isNumber
判断一个值是否是数字
- 基本用法
在需要检查一个变量是否为数字的情况下,可以使用这个函数进行判断,可以避免使用原始值进行比较时可能出现的类型转换错误。
1import { isNumber } from 'radash'
2
3isNumber('hello') // => false
4isNumber(['hello']) // => false
5isNumber(12) // => true
6
- 源码解析
1export const isNumber = (value: any): value is number => {
2 try {
3 // 使用Number函数将value转换为数字
4 // 如果转换后的数字与原始值相等,则返回true,否则返回false
5 return Number(value) === value
6 } catch {
7 return false
8 }
9}
10
这个函数会尝试将 value 转换为数字,如果转换失败(例如,如果 value 是一个字符串且包含非数字字符),将抛出一个异常。因此,在实际使用中,需要捕获可能的异常。
isObject
判断一个值是否是一个对象
-
基本用法
这个函数可以用于检查变量是否为对象,例如在处理对象属性时,以确保它们不是全局变量或未定义。
1import { isObject } from 'radash'
2
3isObject('hello') // => false
4isObject(['hello']) // => false
5isObject(null) // => false
6isObject({ say: 'hello' }) // => true
7
- 源码解析
1export const isObject = (value: any): value is object => {
2 // 使用逻辑与运算符&&首先检查value是否存在,
3 // 并且它的构造函数是否为Object
4 // 这是为了确保接下来要检查的是一个对象
5
6 // 然后,使用value.constructor === Object
7 // 来检查给定的value是否确实是一个对象。
8 return !!value && value.constructor === Object
9 // 这是为了区分普通对象和数组
10 // (因为数组的构造函数也是Object)
11}
12
isPrimitive
检查给定值是否为原始值.
现在有7种基本类型了: number 、 string 、 boolean 、 symbol、 bigint、 undefined、 null。
-
基本用法
在某些情况下,需要判断给定的值是否为原始类型,以避免处理非预期类型的数据。
例如,在 JavaScript 中,有些函数和方法接受原始类型作为参数,但拒绝接受对象或函数作为参数。在这种情况下,可以使用isPrimitive
函数来检查输入值是否为原始类型。
1import { isPrimitive } from 'radash'
2
3isPrimitive(22) // => true
4isPrimitive('hello') // => true
5isPrimitive(['hello']) // => false
6
- 源码解析
1// 用于判断给定的值是否为原始类型
2export const isPrimitive = (value: any): boolean => {
3 return (
4 // 首先,检查value是否为undefined,如果是,则返回true。
5 value === undefined ||
6 // 然后,检查value是否为null,如果是,则返回true。
7 value === null ||
8 (typeof value !== 'object' && typeof value !== 'function')
9 // 接下来,检查value的类型是否不是对象(typeof value !== 'object')
10 // 也不是函数(typeof value !== 'function')
11 // 如果是,则返回true。
12 // 如果value的类型满足上述条件,则返回false
13 )
14}
15
isPromise
确定一个值是否是 Promise
- 基本用法
在异步编程中,经常需要检查某个值是否是一个 Promise 实例。例如,当你需要在一个函数中等待一个 Promise 的结果时,你需要在函数的参数列表中使用 await 关键字。
但是,如果你传入了一个不是 Promise 实例的值,那么它会尝试执行这个值,这可能会导致错误。因此,使用 isPromise 函数来检查传入的值是否是一个 Promise 实例,可以避免潜在的错误。
1import { isPromise } from 'radash'
2
3isPromise('hello') // => false
4isPromise(['hello']) // => false
5isPromise(new Promise(res => res())) // => true
6
- 源码解析
1export const isPromise = (value: any): value is Promise<any> => {
2 if (!value) return false
3 // 如果传入的值是一个Promise实例,那么它应该有一个then方法,且then方法应该是一个函数
4 // 通过检查value.then是否是一个函数,可以判断传入的值是否是一个Promise实例
5 if (!value.then) return false
6 // 使用了一个辅助函数isFunction来检查传入的值是否是一个函数
7 if (!isFunction(value.then)) return false
8 return true
9}
10
这个函数假设所有的传入值都可以被安全地转换为布尔值。
在实际应用中,你可能需要对一些特定的值进行特殊处理,以确保它们不会被错误地识别为 Promise。
例如,对于 null 或 undefined,你可能需要编写额外的逻辑来处理这些情况。
isString
判断一个值是否是一个字符串
- 基本用法
可以使用这个函数来检查一个值是否为字符串类型,从而避免在代码中使用 instanceof
关键字,这样可以提高代码的可读性和安全性。
1import { isString } from 'radash'
2
3isString('hello') // => true
4isString(['hello']) // => false
5
- 源码解析
1export const isString = (value: any): value is string => {
2 // 使用 typeof 和 instanceof 运算符,以及对 value 进行非空检查
3 return typeof value === 'string' || value instanceof String
4}
5
isSymbol
确定一个值是否是一个 Symbol
- 基本用法
这个函数通常用于检查变量是否是一个已经定义的 Symbol,例如使用 const
定义的符号。这对于确保符号名称不会被重复使用非常有用,特别是当符号名称对于应用程序至关重要时。
1import { isSymbol } from 'radash'
2
3isSymbol('hello') // => false
4isSymbol(Symbol('hello')) // => true
5
- 源码解析
1export const isSymbol = (value: any): value is symbol => {
2 // 函数使用逻辑与(&&)操作符来检查value
3 // 是否为undefined或null,以及value是否具有Symbol构造函数
4 // 如果满足这两个条件,函数返回true,否则返回false。
5 return !!value && value.constructor === Symbol
6}
7
最后
感谢读到这里,谢谢支持。感兴趣可以点个赞呀,会坚持更新完的。