【源码学习】Radash(一)Typed 类型判断

Radash

Radash,这个新兴的工具库,以其现代化的设计和对 TypeScript 的原生支持,迅速吸引了开发者的注意。虽然 Radash 是新项目,最近刷很多文章都有推荐,作为 Lodash 的替代,它在 GitHub 上的 star 涨幅很快 ,这表明它是一个有前途的工具库。大家都说好用,而且支持TS,那么我们就来一探究竟吧!

Radash 的特点包括:

  • 零依赖:Radash 不依赖于任何第三方库,使得项目更加轻量级
  • TypeScript 友好:Radash 完全使用 TypeScript 编写,提供了准确的类型定义
  • 现代化功能:Radash 去除了 Lodash 中一些过时的函数,并引入了许多新的实用功能
  • 易于理解和维护:Radash 的源代码易于理解,对新手友好

最主要是看着简单,很容易学习 ~ 现在分的类型也不多,VueUse的坑还没完,这又开新坑了...... 哈哈,先干再说

源码确实很简单,很容易上手和学习,写这样一个系列也不会有厌烦情绪了。 配合着官方例子,加了点自己的解读,若有错误还请批评指出,谢谢(抱拳)!~

Typed

typed.ts 类型判断,也作为整个库的工具方法会被其他文件频繁调用 ~ 在项目中封装这些类型判断可高度借鉴

isArray

  • 基本用法 传入一个值并获取一个布尔值,告诉您该值是否是数组。
ts 复制代码
import { isArray } from 'radash'

isArray('hello') // => false
isArray(['hello']) // => true
  • 源码解析
ts 复制代码
// 当一个变量 isArray 被赋值为 Array.isArray 时
// 它实际上引用的是 Array 构造函数 ( class Array 上的静态方法 )
export const isArray = Array.isArray
// Array.hasOwnProperty('isArray') -> true

isDate

确定值是否为日期

  • 基本用法 确定值是否为日期。不检查输入日期是否有效,仅检查它是 Javascript 日期类型。
ts 复制代码
import { isDate } from 'radash'

isDate(new Date()) // => true
isDate(12) // => false
isDate('hello') // => false
  • 源码分析
ts 复制代码
export const isDate = (value: any): value is Date => {
  // 使用 Object.prototype.toString.call(value) 方法
  // 来获取给定值(value)的类型字符串
  // 然后检查该字符串是否等于'[object Date]'
  return Object.prototype.toString.call(value) === '[object Date]'
}

由于这段代码依赖于 Object.prototype.toString 方法,因此不能在非 ES6 环境中运行。在非 ES6 环境中,你可以使用其他方法来实现相同的功能,例如使用 typeof value === 'object' 来检查值是否是一个对象,然后使用 value instanceof Date 来检查值是否是 Date 类的实例

isEmpty

判断一个值是否为空

  • 基本用法

这个函数主要用于处理复杂类型的值,包括布尔值、null、undefined、数字、日期、函数、符号等

ts 复制代码
import { isEmpty } from 'radash'

isEmpty([]) // => true
isEmpty('') // => true

isEmpty('hello') // => false
isEmpty(['hello']) // => false
  • 源码解析
ts 复制代码
export const isEmpty = (value: any) => {
  // 首先,检查value是否为 布尔值 亦或是 null 或 undefined
  // 如果是,则返回true
  if (value === true || value === false) return true
  if (value === null || value === undefined) return true

  // 然后,检查value是否为数字
  // 若是,判断 value是否等于0 返回该布尔值
  if (isNumber(value)) return value === 0

  // 检查value是否为日期,如果是 value.getTime() 会转换为时间戳
  // 时间戳若有效的,isNaN 为 false,否则为 true
  if (isDate(value)) return isNaN(value.getTime())

  // 检查value是否为函数,如果是,则返回false
  if (isFunction(value)) return false

  // 检查value是否为 Symbol,如果是,则返回false
  if (isSymbol(value)) return false

  // 获取value的长度或大小(如果有的话),并检查其是否为0
  // 为0,则说明是空数组,返回true,否则为 false
  const length = (value as any).length
  if (isNumber(length)) return length === 0
  // 同上,这里针对 Map、Set
  const size = (value as any).size
  if (isNumber(size)) return size === 0

  const keys = Object.keys(value).length
  return keys === 0
}

这段代码使用了类型断言(as any),这可能会导致运行时错误,因为类型断言会跳过类型检查。建议在使用时尽可能地进行类型检查和验证。 这段代码没有处理循环引用的情况,如果 value 是一个对象,并且对象之间存在循环引用,那么 Object.keys(value)可能会导致栈溢出错误。

isEqual

确定两个值是否相等

  • 基本用法

给定两个值,如果它们相等则返回 true。(值比较)主要目的是实现一个通用且高效的比较器,可以用来比较任何类型的数据,包括对象、数组、字符串、数字、布尔值等。

ts 复制代码
import { isEqual } from 'radash'

isEqual(null, null) // => true
isEqual([], []) // => true

isEqual('hello', 'world') // => false
isEqual(22, 'abc') // => false
  • 源码解析
ts 复制代码
export const isEqual = <TType>(x: TType, y: TType): boolean => {
  // Object.is方法来检查x和y是否是同一个对象
  if (Object.is(x, y)) return true

  // 分别检查x和y是否是Date对象。如果是,则比较它们的日期时间戳是否相等
  if (x instanceof Date && y instanceof Date) {
    return x.getTime() === y.getTime()
  }

  // 检查x和y是否是正则对象。如果是,则比较它们的内部表示是否相等。
  if (x instanceof RegExp && y instanceof RegExp) {
    return x.toString() === y.toString()
  }

  // 检查x和y是否不是对象或者null。如果是,则返回false
  if (typeof x !== 'object' || x === null || typeof y !== 'object' || y === null) {
    return false
  }

  // 这里稍微复杂些
  // 如果x和y是对象,则获取它们自己的属性键数组,并遍历这些属性键
  const keysX = Reflect.ownKeys(x as unknown as object) as (keyof typeof x)[]
  const keysY = Reflect.ownKeys(y as unknown as object)

  // 检查y是否具有相同的属性键,并且对应的属性值是否与x相等。
  if (keysX.length !== keysY.length) return false
  for (let i = 0; i < keysX.length; i++) {
    if (!Reflect.has(y as unknown as object, keysX[i])) return false
    if (!isEqual(x[keysX[i]], y[keysX[i]])) return false
  }
  // 如果所有属性都相等,则返回true。
  return true
}

isFloat

判断一个值是否为浮点数

  • 基本用法 传入一个值并获取一个布尔值,告诉您该值是否为浮点型。
ts 复制代码
import { isFloat } from 'radash'

isFloat(12.233) // => true
isFloat(12) // => false
isFloat('hello') // => false
  • 源码解析
ts 复制代码
export const isFloat = (value: any): value is number => {
  // isNumber 函数会检查传入的值是否为 Number 类型,包括整数和浮点数
  // 使用逻辑运算符 % 检查 value 是否为整数
  return isNumber(value) && value % 1 !== 0
  // 如果 value 是浮点数,它将不会被整除
}

isFunction

判断一个值是否是一个函数

  • 基本用法
ts 复制代码
import { isFunction } from 'radash'

isFunction('hello') // => false
isFunction(['hello']) // => false
isFunction(() => 'hello') // => true
  • 源码解析
ts 复制代码
export const isFunction = (value: any): value is Function => {
  // 通过检查value是否为null或undefined,
  // 然后检查value是否有constructor属性,
  // 并判断其call和apply方法是否为函数
  return !!(value && value.constructor && value.call && value.apply)
}

虽然这个函数在大多数情况下能够正确判断传入的值是否为函数,但在某些特殊情况(如 null 或 undefined)中,它会返回 true,这可能不是预期的行为。在处理这些特殊情况时,可能需要额外的检查。

isInt

判断一个值是否为 int

  • 基本用法

这个函数可以用于检查变量是否为有效的整数,从而避免在代码中出现非预期的整数行为。 例如,在处理数字字符串或从用户输入中获取数据时,可以使用 isInt 函数来确保输入的是一个整数。

ts 复制代码
import { isInt } from 'radash'

isInt(12) // => true
isInt(12.233) // => false
isInt('hello') // => false
  • 源码解析
ts 复制代码
export const isInt = (value: any): value is number => {
  // 1. 使用isNumber函数检查value是否为数字(包括整数和浮点数)
  // 2. 使用逻辑运算符&&连接isNumber(value)和value % 1 === 0
  // 3. 如果value是数字且是整数,则返回true,否则返回false
  return isNumber(value) && value % 1 === 0
}
  • isInt 函数不能检查负数和 0 是否为整数,因为它只检查正整数。要检查一个值是否为负整数,可以使用 value < 0 && value % 1 !== 0。
  • isInt 函数不能处理非数字类型的值,例如 null、undefined、string、object 等。在处理这些值时,需要先检查它们是否为数字,然后再使用 isInt 函数。

isNumber

判断一个值是否是数字

  • 基本用法 在需要检查一个变量是否为数字的情况下,可以使用这个函数进行判断,可以避免使用原始值进行比较时可能出现的类型转换错误。
ts 复制代码
import { isNumber } from 'radash'

isNumber('hello') // => false
isNumber(['hello']) // => false
isNumber(12) // => true
  • 源码解析
ts 复制代码
export const isNumber = (value: any): value is number => {
  try {
    // 使用Number函数将value转换为数字
    // 如果转换后的数字与原始值相等,则返回true,否则返回false
    return Number(value) === value
  } catch {
    return false
  }
}

这个函数会尝试将 value 转换为数字,如果转换失败(例如,如果 value 是一个字符串且包含非数字字符),将抛出一个异常。因此,在实际使用中,需要捕获可能的异常。

isObject

判断一个值是否是一个对象

  • 基本用法
    这个函数可以用于检查变量是否为对象,例如在处理对象属性时,以确保它们不是全局变量或未定义。
ts 复制代码
import { isObject } from 'radash'

isObject('hello') // => false
isObject(['hello']) // => false
isObject(null) // => false
isObject({ say: 'hello' }) // => true
  • 源码解析
ts 复制代码
export const isObject = (value: any): value is object => {
  // 使用逻辑与运算符&&首先检查value是否存在,
  // 并且它的构造函数是否为Object
  // 这是为了确保接下来要检查的是一个对象

  // 然后,使用value.constructor === Object
  // 来检查给定的value是否确实是一个对象。
  return !!value && value.constructor === Object
  // 这是为了区分普通对象和数组
  // (因为数组的构造函数也是Object)
}

isPrimitive

检查给定值是否为原始值.

现在有7种基本类型了: number 、 string 、 boolean 、 symbol、 bigint、 undefined、 null。

  • 基本用法
    在某些情况下,需要判断给定的值是否为原始类型,以避免处理非预期类型的数据。 例如,在 JavaScript 中,有些函数和方法接受原始类型作为参数,但拒绝接受对象或函数作为参数。在这种情况下,可以使用 isPrimitive 函数来检查输入值是否为原始类型。
ts 复制代码
import { isPrimitive } from 'radash'

isPrimitive(22) // => true
isPrimitive('hello') // => true
isPrimitive(['hello']) // => false
  • 源码解析
ts 复制代码
// 用于判断给定的值是否为原始类型
export const isPrimitive = (value: any): boolean => {
  return (
    // 首先,检查value是否为undefined,如果是,则返回true。
    value === undefined ||
    // 然后,检查value是否为null,如果是,则返回true。
    value === null ||
    (typeof value !== 'object' && typeof value !== 'function')
    // 接下来,检查value的类型是否不是对象(typeof value !== 'object')
    // 也不是函数(typeof value !== 'function')
    // 如果是,则返回true。
    // 如果value的类型满足上述条件,则返回false
  )
}

isPromise

确定一个值是否是 Promise

  • 基本用法

在异步编程中,经常需要检查某个值是否是一个 Promise 实例。例如,当你需要在一个函数中等待一个 Promise 的结果时,你需要在函数的参数列表中使用 await 关键字。

但是,如果你传入了一个不是 Promise 实例的值,那么它会尝试执行这个值,这可能会导致错误。因此,使用 isPromise 函数来检查传入的值是否是一个 Promise 实例,可以避免潜在的错误。

ts 复制代码
import { isPromise } from 'radash'

isPromise('hello') // => false
isPromise(['hello']) // => false
isPromise(new Promise(res => res())) // => true
  • 源码解析
ts 复制代码
export const isPromise = (value: any): value is Promise<any> => {
  if (!value) return false
  // 如果传入的值是一个Promise实例,那么它应该有一个then方法,且then方法应该是一个函数
  // 通过检查value.then是否是一个函数,可以判断传入的值是否是一个Promise实例
  if (!value.then) return false
  // 使用了一个辅助函数isFunction来检查传入的值是否是一个函数
  if (!isFunction(value.then)) return false
  return true
}

这个函数假设所有的传入值都可以被安全地转换为布尔值。 在实际应用中,你可能需要对一些特定的值进行特殊处理,以确保它们不会被错误地识别为 Promise。 例如,对于 null 或 undefined,你可能需要编写额外的逻辑来处理这些情况。

isString

判断一个值是否是一个字符串

  • 基本用法

可以使用这个函数来检查一个值是否为字符串类型,从而避免在代码中使用 instanceof 关键字,这样可以提高代码的可读性和安全性。

ts 复制代码
import { isString } from 'radash'

isString('hello') // => true
isString(['hello']) // => false
  • 源码解析
ts 复制代码
export const isString = (value: any): value is string => {
  // 使用 typeof 和 instanceof 运算符,以及对 value 进行非空检查
  return typeof value === 'string' || value instanceof String
}

isSymbol

确定一个值是否是一个 Symbol

  • 基本用法

这个函数通常用于检查变量是否是一个已经定义的 Symbol,例如使用 const 定义的符号。这对于确保符号名称不会被重复使用非常有用,特别是当符号名称对于应用程序至关重要时。

ts 复制代码
import { isSymbol } from 'radash'

isSymbol('hello') // => false
isSymbol(Symbol('hello')) // => true
  • 源码解析
ts 复制代码
export const isSymbol = (value: any): value is symbol => {
  // 函数使用逻辑与(&&)操作符来检查value
  // 是否为undefined或null,以及value是否具有Symbol构造函数
  // 如果满足这两个条件,函数返回true,否则返回false。
  return !!value && value.constructor === Symbol
}

最后

感谢读到这里,谢谢支持。感兴趣可以点个赞呀,会坚持更新完的。

相关推荐
拾光拾趣录3 分钟前
CSS 深入解析:提升网页样式技巧与常见问题解决方案
前端·css
莫空00004 分钟前
深入理解JavaScript属性描述符:从数据属性到存取器属性
前端·面试
guojl4 分钟前
深度剖析Kafka读写机制
前端
FogLetter5 分钟前
图片懒加载:让网页飞起来的魔法技巧 ✨
前端·javascript·css
Mxuan6 分钟前
vscode webview 插件开发(精装篇)
前端
Mxuan7 分钟前
vscode webview 插件开发(交付篇)
前端
Mxuan8 分钟前
vscode 插件与 electron 应用跳转网页进行登录的实践
前端
拾光拾趣录8 分钟前
JavaScript 加载对浏览器渲染的影响
前端·javascript·浏览器
Codebee8 分钟前
OneCode图表配置速查手册
大数据·前端·数据可视化
然我9 分钟前
React 开发通关指南:用 HTML 的思维写 JS🚀🚀
前端·react.js·html