Skip to content
小巧实用的 JavaScript 工具类库。
TypeScript CSS
Branch: master
Clone or download

README.md

logo

NPM Version Build Status Coverage Status Size Gzip Size License

小巧实用的 JavaScript 工具类库。

https://fjc0k.github.io/vtils/vtils

特性

  • 源于日常项目实践,更实用
  • 使用 TypeScript 编写,类型友好
  • 支持摇树优化(Tree Shaking),只引入使用到的工具
  • 浏览器、Node、小程序多端兼容

说明

vtils 自身并不包括一些已有成熟库的工具,如时间处理、网络请求等,在此做下推荐:

安装

# yarn
yarn add vtils

# or, npm
npm i vtils --save

你也可通过 CDN 安装,然后使用全局变量 vtils 访问相关工具:

<script src="https://cdn.jsdelivr.net/npm/vtils@2.55.0/lib/index.umd.min.js" crossorigin="anonymous"></script>

<script>
  if (vtils.inBrowser()) {
    alert('您在浏览器中...')
  }
</script>

使用

在线体验:https://stackblitz.com/edit/vtils

import { inBrowser, shuffle } from 'vtils'

if (inBrowser()) {
  alert('您在浏览器中...')
}

alert(shuffle([1, 2, 3, 4, 5]))

目录

📦 工具函数

👇 👇 👇 👇
assign base64Decode base64Encode base64UrlDecode
base64UrlEncode castArray chunk clamp
combine createURIQuery debounce dedent
defaultIndexTo defaultTo endsWith entries
escapeRegExp expectType fill flat
flexible forOwn getGlobal getType
groupBy has ii inAndroid
inBrowser inIOS inNode inRange
inWechatMiniProgram inWechatWebview includes indent
isArguments isArray isBoolean isChineseIDCardNumber
isDate isEmail isEmpty isEqualArray
isFinite isFunction isHan isInteger
isNaN isNegativeInteger isNil isNull
isNumber isNumeric isObject isPlainObject
isPositiveInteger isPossibleChineseMobilePhoneNumber isPossibleChineseName isPromiseLike
isRegExp isString isUndefined isUrl
jestExpectEqual keyBy keys last
loadResource loop mapValues memoize
noop omit orderBy padEnd
padStart parallel parseCSSValue parseURIQuery
partial partialBy pick placeKitten
pluck randomString range remove
removeByValue repeat result round
roundDown roundUp safeGet sample
sequential shuffle startsWith sum
sumBy throttle times tryGet
unique values wait

📦 工具类

👇 👇 👇
Disposer EasyStorage EasyStorageAdapter
EasyStorageAdapterBrowser EasyStorageAdapterBrowserLocalStorage EasyStorageAdapterBrowserSessionStorage
EasyStorageAdapterMemory EasyStorageAdapterWeapp EasyValidator
EventBus StructuredListTransformer Wechat
XUrl

📦 工具类型

👇 👇 👇 👇 👇 👇 👇 👇 👇
AnyFunction AnyObject AsyncOrSync AsyncReturnType Brand Defined If IsNever LiteralUnion
Merge Omit OneOrMore PartialBy RequiredBy ValueOf

工具列表

📦 工具函数

assign

源码 | API | 回目录

分配来源对象的可枚举属性到目标对象上。

来源对象的应用规则是从左到右,随后的下一个对象的属性会覆盖上一个对象的属性。

assign(
  {},
  { x: 1 },
  { y: 2 },
  { x: 5, z: 9 },
)
// => { x: 5, y: 2, z: 9 }

base64Decode

源码 | API | 回目录

返回 base64 解码后的字符串。

base64Decode('dnRpbHM=') // => vtils
base64Decode('5Lit5Zu9') // => 中国
base64Decode('8J+RqOKAjfCfkrs=') // => 👨‍💻

base64Encode

源码 | API | 回目录

返回 base64 编码后的字符串。

base64Encode('vtils') // => dnRpbHM=
base64Encode('中国') // => 5Lit5Zu9
base64Encode('👨‍💻') // => 8J+RqOKAjfCfkrs=

base64UrlDecode

源码 | API | 回目录

返回 base64url 解码后的字符串。

base64UrlDecode('dnRpbHM') // => vtils
base64UrlDecode('5Lit5Zu9') // => 中国
base64UrlDecode('8J-RqOKAjfCfkrs') // => 👨‍💻

base64UrlEncode

源码 | API | 回目录

返回 base64url 编码后的字符串。

base64UrlEncode('vtils') // => dnRpbHM
base64UrlEncode('中国') // => 5Lit5Zu9
base64UrlEncode('👨‍💻') // => 8J-RqOKAjfCfkrs

castArray

源码 | API | 回目录

如果 value 是数组,直接返回;如果 value 不是数组,返回 [value]

castArray([123, 456]) // => [123, 456]
castArray(123) // => [123]
castArray('hello') // => ['hello']
castArray(null) // => [null]

chunk

源码 | API | 回目录

arr 拆分成多个 size 长度的区块,并将它们组合成一个新数组返回。

如果 arr 无法等分,且设置了 filler 函数,剩余的元素将被 filler 函数的返回值填充。

const arr = [1, 2, 3, 4, 5, 6]
chunk(arr, 2) // => [[1, 2], [3, 4], [5, 6]]
chunk(arr, 3) // => [[1, 2, 3], [4, 5, 6]]
chunk(arr, 4) // => [[1, 2, 3, 4], [5, 6]]
chunk(arr, 4, index => index) // => [[1, 2, 3, 4], [5, 6, 0, 1]]

clamp

源码 | API | 回目录

返回限制在最小值和最大值之间的值。

clamp(50, 0, 100) // => 50
clamp(50, 0, 50) // => 50
clamp(50, 0, 49) // => 49
clamp(50, 51, 100) // => 51

combine

源码 | API | 回目录

创建一个对象,用一个数组的值作为其键名,另一个数组的值作为其值。

combine(
  [1, 'hi'],
  [0, false],
) // => { 1: 0, hi: false }

createURIQuery

源码 | API | 回目录

创建 URI 查询字符串。

createURIQuery({ x: 1, y: 'z' }) // => x=1&y=z

debounce

源码 | API | 回目录

创建一个去抖函数,将触发频繁的事件合并成一次执行。

该函数被调用后,计时 wait 毫秒后调用 fn 函数。若在 wait 毫秒内该函数再次被调用,则重新开始计时。

一个应用场景:监听输入框的 input 事件发起网络请求。

document.querySelector('#input').oninput = debounce(
  e => {
    console.log(e.target.value)
  },
  500,
)

dedent

源码 | API | 回目录

首先,每一行紧跟前导空白的插入值为多行时,保持缩进。

然后,移除每一行的公共前导空白。

const text = 'hello\nworld'
dedent`
  ${text}
    -.-
` // => 'hello\nworld\n  -.-'

移除文本中每一行的公共前导空白。

dedent(`
  hello
  world
    -.-
`) // => 'hello\nworld\n  -.-'

defaultIndexTo

源码 | API | 回目录

index-1 时,返回 defaultIndex

defaultIndexTo(-1, 0) // => 0
defaultIndexTo(0, 0) // => 0
defaultIndexTo(1, 0) // => 1

defaultTo

源码 | API | 回目录

检查 value 是否是 nullundefinedNaN,或者是否在 extraPredictions 中(若提供了 extraPredictions),是则返回 defaultValue,否则返回 value

defaultTo(1, 2) // => 1
defaultTo(1, 2, [1]) // => 2
defaultTo(NaN, 2) // => 2
defaultTo(null, 2) // => 2
defaultTo(undefined, 2) // => 2

endsWith

源码 | API | 回目录

检查 str 是否以 needle 结尾。

endsWith('hello', 'llo') // => true
endsWith('hello', 'he') // => false

entries

源码 | API | 回目录

创建一个 data 对象自身可枚举属性的键值对数组,但不保证每次创建的数组顺序一致。

entries({
  x: 1,
  y: 2,
}) // => [['x', 1], ['y', 2]]

escapeRegExp

源码 | API | 回目录

转义正则表达式中的特殊字符。

escapeRegExp('github.com') // => 'github\\.com'

expectType

源码 | API | 回目录

fill

源码 | API | 回目录

使用 value 来填充(替换) arr,从 start 位置开始, 到 end 位置结束(但不包括 end 位置)。

fill(Array(5), () => 1) // => [1, 1, 1, 1, 1]
fill(Array(3), (value, index) => index) // => [0, 1, 2]

flat

源码 | API | 回目录

提取数组中所有子数组的元素合并为一个新数组返回。

flat([
  [1, 2, '3'],
  ['', 0],
]) // => [1, 2, '3', '', 0]

flexible

源码 | API | 回目录

移动端屏幕适配。

forOwn

源码 | API | 回目录

遍历对象的可枚举属性。若遍历函数返回 false,遍历会提前退出。

注:基于你传入的 obj,遍历函数中 key 的类型可能为 number,但在运行时,key 始终为 string,因此,你应该始终把 key 当作 string 处理。(为什么会这样?https://github.com/microsoft/TypeScript/pull/12253#issuecomment-263132208)

forOwn(
  { x: '1', y: 2 },
  (value, key) => {
    console.log(key, value)
  }
)

getGlobal

源码 | API | 回目录

获取全局对象。

// 浏览器中
getGlobal() // => window
// Node 中
getGlobal() // => global

getType

源码 | API | 回目录

检测 value 的类型。

getType(1) // => 'Number'
getType(true) // => 'Boolean'
getType([]) // => 'Array'
getType(/hello/) // => 'RegExp'

groupBy

源码 | API | 回目录

根据 iteratee 返回的值对 data 进行分组。

groupBy(
  [
    { type: 1, name: '石头' },
    { type: 3, name: '花生' },
    { type: 2, name: '鲸鱼' },
    { type: 1, name: '树木' },
    { type: 2, name: '鲨鱼' },
  ],
  item => item.type,
)
// => {
// =>   1: [
// =>     { type: 1, name: '石头' },
// =>     { type: 1, name: '树木' },
// =>   ],
// =>   2: [
// =>     { type: 2, name: '鲸鱼' },
// =>     { type: 2, name: '鲨鱼' },
// =>   ],
// =>   3: [
// =>     { type: 3, name: '花生' },
// =>   ],
// => }

has

源码 | API | 回目录

检查 key 是否是对象 obj 自身的属性。

const obj = { x: 1, 2: 'y' }
has(obj, 'x') // => true
has(obj, 2) // => true
has(obj, 'toString') // => false

ii

源码 | API | 回目录

立即调用函数并返回其返回值。

注:ii = immediately invoke

ii(() => 1) // => 1

inAndroid

源码 | API | 回目录

检查是否在 Android 设备中。

// Android 设备中
inAndroid() // => true
inAndroid(
  () => console.log('你在 Android 设备中'),
)

inBrowser

源码 | API | 回目录

检查是否在浏览器环境中。

// 浏览器中
inBrowser() // => true
inBrowser(
  () => console.log('你在浏览器中'),
)

inIOS

源码 | API | 回目录

检查是否在 iOS 设备中。

// iOS 设备中
inIOS() // => true
inIOS(
  () => console.log('你在 iOS 设备中'),
)

inNode

源码 | API | 回目录

检查是否在 Node 环境中。

// Node 中
inNode() // => true
inNode(
  () => console.log('你在 Node 中'),
)

inRange

源码 | API | 回目录

检查 value 是否在某区间内。

// 2 是否在区间 (0, 2) 内
inRange(2, 0, 2, InRangeIntervalType.open) // => false

// 2 是否在区间 [0, 2] 内
inRange(2, 0, 2, InRangeIntervalType.closed) // => true

// 2 是否在区间 [0, 2) 内
inRange(2, 0, 2, InRangeIntervalType.leftClosedRightOpen) // => false

// 2 是否在区间 (0, 2] 内
inRange(2, 0, 2, InRangeIntervalType.leftOpenRightClosed) // => true

inWechatMiniProgram

源码 | API | 回目录

检查是否在微信小程序环境中。

// 微信小程序中
inWechatMiniProgram() // => true
inWechatMiniProgram(
  () => console.log('你在微信小程序中'),
)

inWechatWebview

源码 | API | 回目录

检查是否在微信浏览器环境中。

// 微信浏览器中
inWechatWebview() // => true
inWechatWebview(
  () => console.log('你在微信浏览器中'),
)

includes

源码 | API | 回目录

检索值 value 是否在数组 arr 中。

includes([1, 2, 3], 1) // => true
includes([NaN, 2, 3], NaN) // => true
includes([1, 2, 3], 4) // => false

检索可枚举属性值 value 是否在对象 obj 中。

includes({ x: 1, y: 2 }, 1) // => true
includes({ x: 1, y: 2 }, 3) // => false

检索值 value 是否在字符串 str 中。

includes('hello', 'h') // => true
includes('hello', 'll') // => true
includes('hello', '123') // => false

indent

源码 | API | 回目录

每一行紧跟前导空白的插入值为多行时,保持缩进。

const text = 'hello\nworld'
indent`  ${text}` // => '  hello\n  world'

给文本每一行的开始加上一个前导字符串。

indent('hello\nworld', '-> ')
// => '-> hello\n-> world'

给文本每一行的开始加上一个前导字符串,前导字符串由回调函数返回。

indent(
  'hello\nworld',
  (lineStr, lineIndex) => `${lineIndex + 1}. `,
)
// => '1. hello\n2. world'

isArguments

源码 | API | 回目录

检查 value 是否是一个 arguments 对象。

function myFunction() {
  console.log(isArguments(arguments)) // true
}

isArray

源码 | API | 回目录

检查 value 是否是一个数组。

isArray(['x']) // => true
isArray('x') // => false

isBoolean

源码 | API | 回目录

检查 value 是否是一个布尔值。

isBoolean(true) // => true
isBoolean(false) // => true
isBoolean('true') // => false

isChineseIDCardNumber

源码 | API | 回目录

检查 value 是否是合法的中国大陆居民 18 位身份证号码。

isChineseIDCardNumber('123456') // => false

isDate

源码 | API | 回目录

检查 value 是否是一个日期。

isDate(new Date()) // => true

isEmail

源码 | API | 回目录

检查 value 是否是一个邮件地址。

isEmail('hello@foo.bar') // => true
isEmail('hello@foo') // => false

isEmpty

源码 | API | 回目录

检查 value 是否是空值,包括:undefinednull''falsetrue[]{}

isEmpty(undefined) // => true
isEmpty(null) // => true
isEmpty('') // => true
isEmpty(false) // => true
isEmpty(true) // => true
isEmpty([]) // => true
isEmpty({}) // => true

isEqualArray

源码 | API | 回目录

检查给定的数组的各项是否相等。

isEqualArray([1], [1]) // => true
isEqualArray([1], [5]) // => false

isFinite

源码 | API | 回目录

检查 value 是否是原始有限数值。

isFinite(1) // => true
isFinite(Infinity) // => false

isFunction

源码 | API | 回目录

检查 value 是否是一个函数。

isFunction(() => {}) // => true
isFunction(2000) // => false

isHan

源码 | API | 回目录

检查 value 是否全是汉字。

isHan('hello') // => false
isHan('嗨咯') // => true

isInteger

源码 | API | 回目录

检查 value 是否是一个整数。

isInteger(1) // => true
isInteger(1.2) // => false
isInteger(-1) // => true

isNaN

源码 | API | 回目录

检查 value 是否是 NaN

isNaN(NaN) // => true
isNaN(2) // => false

isNegativeInteger

源码 | API | 回目录

检查 value 是否是一个负整数。

isNegativeInteger(-1) // => true
isNegativeInteger(1) // => false

isNil

源码 | API | 回目录

检查 value 是否是 nullundefined

isNil(null) // => true
isNil(undefined) // => true

isNull

源码 | API | 回目录

检查 value 是否是 null

isNull(null) // => true

isNumber

源码 | API | 回目录

检查 value 是否是一个数字。

注:NaN 不被认为是数字。

isNumber(1) // => true
isNumber(0.1) // => true
isNumber(NaN) // => false

isNumeric

源码 | API | 回目录

检查 value 是否是一个数值。

注:Infinity-InfinityNaN 不被认为是数值。

isNumeric(1) // => true
isNumeric('1') // => true

isObject

源码 | API | 回目录

检查 value 是否是一个对象。

isObject({}) // => true
isObject(() => {}) // => true
isObject(null) // => false

isPlainObject

源码 | API | 回目录

检查 value 是否是一个普通对象。

isPlainObject({}) // => true
isPlainObject(Object.create(null)) // => true
isPlainObject(() => {}) // => false

isPositiveInteger

源码 | API | 回目录

检查 value 是否是一个正整数。

isPositiveInteger(1) // => true
isPositiveInteger(-1) // => false

isPossibleChineseMobilePhoneNumber

源码 | API | 回目录

检测 number 是否可能是中国的手机号码。

isPossibleChineseMobilePhoneNumber(18000030000) // => true
isPossibleChineseMobilePhoneNumber(10086) // => false

isPossibleChineseName

源码 | API | 回目录

检测 value 是否可能是中国人的姓名,支持少数名族姓名中间的 · 号。

isPossibleChineseName('') // => false
isPossibleChineseName('鲁迅') // => true
isPossibleChineseName('买买提·吐尔逊') // => true

isPromiseLike

源码 | API | 回目录

检查 value 是否像 Promise

isPromiseLike(Promise.resolve()) // => true

isRegExp

源码 | API | 回目录

检查 value 是否是一个正则对象。

isRegExp(/hello/) // => true
isRegExp(new RegExp('hello')) // => true

isString

源码 | API | 回目录

检查 value 是否是一个字符串。

isString('') // => true
isString('hello') // => true

isUndefined

源码 | API | 回目录

检查 value 是否等于 undefined

isUndefined(undefined) // => true
isUndefined(void 0) // => true

isUrl

源码 | API | 回目录

检查 value 是否是一个有效的网址,仅支持 httphttps 协议,支持 IP 域名。

isUrl('http://foo.bar') // => true
isUrl('https://foo.bar/home') // => true

jestExpectEqual

源码 | API | 回目录

这是一个 jest 测试辅助函数,等同于 expect(actual).toEqual(expected),只不过是加上了类型。

keyBy

源码 | API | 回目录

根据 iteratee 返回的键对 data 进行分组,但只保留最后一个结果。

keyBy(
  [
    { type: 1, name: '石头' },
    { type: 3, name: '花生' },
    { type: 2, name: '鲸鱼' },
    { type: 1, name: '树木' },
    { type: 2, name: '鲨鱼' },
  ],
  item => item.type,
)
// => {
// =>   1: { type: 1, name: '树木' },
// =>   2: { type: 2, name: '鲨鱼' },
// =>   3: { type: 3, name: '花生' },
// => }

keys

源码 | API | 回目录

返回 obj 的可枚举属性组成的数组。

注:基于你传入的 obj,返回的 key 的类型可能为 number,但在运行时,key 始终为 string,因此,你应该始终把 key 当作 string 处理。(为什么会这样?https://github.com/microsoft/TypeScript/pull/12253#issuecomment-263132208)

keys({ x: 1, 2: 'y' }) // => ['x', '2'] 或 ['2', 'x']

last

源码 | API | 回目录

返回数组 arr 的最后一项。

last([1, 2, 3]) // => 3

loadResource

源码 | API | 回目录

加载图片、代码、样式等资源。

loadResource([
  'https://foo.bar/all.js',
  'https://foo.bar/all.css',
  'https://foo.bar/logo.png',
  {
    type: LoadResourceUrlType.js,
    path: 'https://s1.foo.bar/js/full',
    alternatePath: 'https://s2.foo.bar/js/full',
  },
]).then(() => {
  // 资源加载完成后的操作
})

loop

源码 | API | 回目录

每隔 interval 毫秒执行一次 callback

// 每隔 1000 毫秒输出一次 hello
const stop = loop(
  1000,
  () => console.log('hello'),
)

mapValues

源码 | API | 回目录

映射对象的可枚举属性值为一个新的值。

mapValues(
  { x: 1, y: 2 },
  value => value + 10,
)
// => { x: 11, y: 12 }

memoize

源码 | API | 回目录

函数结果缓存。

let i = 0
const fn = memoize(() => i++)
fn() // => 0
fn() // => 0

noop

源码 | API | 回目录

无操作函数。

noop() // => undefined

omit

源码 | API | 回目录

创建一个从 obj 中剔除选中的可枚举属性的对象。

omit({ x: 1, y: 2 }, ['x']) // => { y: 2 }

orderBy

源码 | API | 回目录

允许指定一个或多个规则对数据进行排序。

orderBy(
  ['x', 'xyz', 'xy'],
  {
    iteratee: item => item.length,
    type: OrderByRuleType.desc,
  },
)
// => ['xyz', 'xy', 'x']

padEnd

源码 | API | 回目录

str 右侧填充字符。

padEnd('姓名', 4, '*') // => 姓名**

padStart

源码 | API | 回目录

str 左侧填充字符。

padStart('姓名', 4, '*') // => **姓名

parallel

源码 | API | 回目录

并行执行任务,同步任务异步任务 皆可。

parallel([
  () => 1,
  async () => 'hello',
]).then(res => {
  // => [1, 'hello']
})

parseCSSValue

源码 | API | 回目录

解析 CSS 值的数值和单位。

parseCSSValue('12px') // => { value: 12, unit: 'px' }
parseCSSValue(12) // => { value: 12, unit: 'px' }
parseCSSValue('12%') // => { value: 12, unit: '%' }

parseURIQuery

源码 | API | 回目录

解析 URI 查询字符串。

兼容以 ? 开头的查询字符串,因此你可以直接传入 location.search 的值。

parseURIQuery('x=1&y=z') // => { x: '1', y: 'z' }
parseURIQuery('?x=1&y=z') // => { x: '1', y: 'z' }
parseURIQuery(
  'x=1&y=z',
  parameters => ({
    ...parameters,
    x: Number(parameters.x),
  }),
) // => { x: 1, y: 'z' }

partial

源码 | API | 回目录

TypeScript 中 Partial 的函数版本。

partial({ x: 1 } as const) // => { x?: number }

partialBy

源码 | API | 回目录

TypeScript 中 PartialBy 的函数版本。

partialBy(
  { x: 1, y: 2 } as const,
  ['x'],
) // => { x?: number, y: number }

pick

源码 | API | 回目录

创建一个从 obj 中选中的可枚举属性的对象。

pick({ x: 1, y: 2 }, ['x']) // => { x: 1 }

placeKitten

源码 | API | 回目录

给定大小获取占位猫咪图片,图片来自:https://placekitten.com/

placeKitten(100) // => https://placekitten.com/100/100

给定宽高获取占位猫咪图片,图片来自:https://placekitten.com/

placeKitten(100, 200) // => https://placekitten.com/100/200

pluck

源码 | API | 回目录

将数据中每一项的迭代值组合成一个数组返回。

pluck(
  [{ id: 1, name: 'Jay' }, { id: 2, name: 'Lily' }],
  item => item.name,
) // => ['Jay', 'Lily']

将数据中每一项的迭代值组合成一个对象返回,后者会覆盖前者。

pluck(
  [{ id: 1, name: 'Jay' }, { id: 2, name: 'Lily' }],
  item => item.name,
  item => item.id,
) // => { 1: 'Jay', 2: 'Lily' }

randomString

源码 | API | 回目录

生成一个随机字符串。

randomString() // => m481rnmse1m

range

源码 | API | 回目录

创建一个包含从 startend,但不包含 end 本身范围数字的数组。

range(0, 5) // => [0, 1, 2, 3, 4]
range(0, -5, -1) // => [0, -1, -2, -3, -4]

remove

源码 | API | 回目录

根据索引原地删除数组中指定的值。

remove([1, 2, 3], 1) // => [1, 3]

removeByValue

源码 | API | 回目录

原地删除数组中第一次出现的指定值。

removeByValue([1, 2, 3], 1) // => [2, 3]

repeat

源码 | API | 回目录

重复 n 次给定字符串。

repeat('a', 5) // => aaaaa

result

源码 | API | 回目录

以数组的方式返回异步操作的结果。

// 异步操作成功
const [err, res] = await result(new Promise(resolve => resolve('ok'))) // => [null, 'ok']

// 异步操作出错
const [err, res] = await result(new Promise((resolve, reject) => reject('err'))) // => ['err']

以数组的方式返回函数执行的结果,如果函数返回一个异步操作,将会执行该异步操作并将其结果作为函数执行的结果返回。

// 函数执行成功
const [err, res] = await result(() => 'ok') // => [null, 'ok']
const [err, res] = await result(() => new Promise(resolve => resolve('ok'))) // => [null, 'ok']

// 函数执行出错
const [err, res] = await result(() => { throw 'err' }) // => ['err']
const [err, res] = await result(() => new Promise((resolve, reject) => reject('err'))) // => ['err']

round

源码 | API | 回目录

对传入的数字按给定的精度四舍五入后返回。

round(3.456) // => 3
round(3.456, 1) // => 3.5
round(3.456, 2) // => 3.46
round(345, -2) // => 300

roundDown

源码 | API | 回目录

对传入的数字按给定的精度向下取值后返回。

roundDown(3.456) // => 3
roundDown(3.456, 1) // => 3.4
roundDown(3.456, 2) // => 3.45
roundDown(345, -2) // => 300

roundUp

源码 | API | 回目录

对传入的数字按给定的精度向上取值后返回。

roundUp(3.456) // => 4
roundUp(3.456, 1) // => 3.5
roundUp(3.456, 2) // => 3.46
roundUp(345, -2) // => 400

safeGet

源码 | API | 回目录

sample

源码 | API | 回目录

从数组中随机获取一个元素。

sample([1, 2, 3]) // => 1 或 2 或 3

从对象中随机获取一个可枚举属性的值。

sample({ x: 1, y: 2, z: 3 }) // => 1 或 2 或 3

sequential

源码 | API | 回目录

顺序执行任务,同步任务异步任务 皆可。

sequential([
  () => 1,
  async () => 'hello',
]).then(res => {
  // => [1, 'hello']
})

shuffle

源码 | API | 回目录

打乱一个数组。

shuffle([1, 2]) // => [1, 2] 或 [2, 1]

startsWith

源码 | API | 回目录

检查 str 是否以 needle 开头。

startsWith('hello', 'he') // => true
startsWith('hello', 'llo') // => false

sum

源码 | API | 回目录

计算传入值的总和。

sum([1, 2, 3]) // => 6

sumBy

源码 | API | 回目录

根据 iteratee 返回的结果计算传入值的总和。

sumBy(
  [
    { count: 1 },
    { count: 2 },
    { count: 3 },
  ],
  item => item.count,
)
// => 6

throttle

源码 | API | 回目录

创建一个节流函数,给函数设置固定的执行速率。

  • 该函数首次被调用时,会立即调用 fn 函数,并记录首次调用时间。
    • 该函数第二次被调用时:
      • 如果该次调用时间在首次调用时间的 wait 区间内,timer = setTimeout(操作, 时间差)
        • 该函数再次被调用时:
          • 如果该次调用时间在首次调用时间的 wait 区间内,什么都不做;
          • 否则,清除首次调用时间和计时器,回到第一步。
      • 否则,清除首次调用时间,回到第一步。

一个应用场景:监听窗口的 resize 事件响应相关操作。

window.addEventListener(
  'resize',
  throttle(
    () => console.log('窗口大小改变后的操作'),
    1000,
  ),
)

times

源码 | API | 回目录

调用函数 n 次,将每次的调用结果存进数组并返回。

times(4, () => {
  // 这里将会执行 4 次
})

tryGet

源码 | API | 回目录

尝试执行 accessor 返回值,若其报错,返回默认值 defaultValue

const obj = { x: 1 }
tryGet(() => obj.x, 2) // => 1
tryGet(() => obj.x.y, 2) // => 2

尝试执行 accessor 返回值,若其报错,返回 undefined

const obj = { x: 1 }
tryGet(() => obj.x) // => 1
tryGet(() => obj.x.y) // => undefined

unique

源码 | API | 回目录

将给定的数组去重后返回。

unique([1, 2, 1, 3]) // => [1, 2, 3]

values

源码 | API | 回目录

返回 obj 自身可枚举属性值组成的数组。

values({ x: 1, 2: 'y' }) // => [1, 'y'] 或 ['y', 1]

wait

源码 | API | 回目录

等待一段时间。

wait(1000).then(() => {
  // 等待 1000 毫秒后执行
})

📦 工具类

Disposer

源码 | API | 回目录

资源释放器。

const disposer = new Disposer()
const timer = setInterval(
  () => console.log('ok'),
  1000,
)
disposer.add(() => clearInterval(timer))
document.querySelector('#stop').onclick = () => {
  disposer.dispose()
}

EasyStorage

源码 | API | 回目录

EasyStorageAdapter

源码 | API | 回目录

EasyStorageAdapterBrowser

源码 | API | 回目录

EasyStorageAdapterBrowserLocalStorage

源码 | API | 回目录

EasyStorageAdapterBrowserSessionStorage

源码 | API | 回目录

EasyStorageAdapterMemory

源码 | API | 回目录

EasyStorageAdapterWeapp

源码 | API | 回目录

微信小程序 Storage 适配器。

由于微信小程序的 wx.getStorageSync 方法对于不存在的项目会返回 空字符串,导致无法判断项目是否存在,因此,该适配器对存储的内容做了一层封装,以保证相关操作的结果可确定。

EasyValidator

源码 | API | 回目录

数据对象验证器。

interface Data {
  name: string,
  phoneNumber: string,
  pass1: string,
  pass2: string,
}
const ev = new EasyValidator<Data>([
  {
    key: 'name',
    type: 'chineseName',
    message: '请输入真实姓名',
  },
  {
    key: 'phoneNumber',
    type: 'chineseMobilePhoneNumber',
    message: '请输入正确的手机号码',
  },
  {
    key: 'phoneNumber',
    test: async ({ phoneNumber }, { updateMessage }) => {
      const result = await checkPhoneNumberAsync(phoneNumber)
      if (!result.valid) {
        updateMessage(result.message)
        return false
      }
    },
    message: '请输入正确的手机号码'
  },
  {
    key: 'pass1',
    test: ({ pass1 }) => pass1.length > 6,
    message: '密码应大于6位',
  },
  {
    key: 'pass2',
    test: ({ pass1, pass2 }) => pass2 === pass1,
    message: '两次密码应一致',
  },
])
ev.validate({
  name: '方一一',
  phoneNumber: '18087030070',
  pass1: '1234567',
  pass2: '12345678'
}).then(res => {
  // => { valid: false, ... }
})

EventBus

源码 | API | 回目录

事件巴士,管理事件的发布与订阅。

const bus = new EventBus<{
  success: () => void,
  error: (message: string) => void,
}>()
const unbindSuccessListener = bus.on('success', () => {
  console.log('成功啦')
})
const unbindErrorListener = bus.once('error', message => {
  console.error(message)
})
bus.emit('success')
bus.emit('error', '出错啦')
unbindSuccessListener()
bus.off('error')

StructuredListTransformer

源码 | API | 回目录

结构化列表数据转换器。

Wechat

源码 | API | 回目录

对微信 JSSDK 的封装。

const wechat = new Wechat()
getWechatConfigAsync().then(config => {
  wechat.config(config)
})
wechat.updateShareData({
  title: '分享标题',
  desc: '分享描述',
  link: '分享链接',
  imgUrl: '缩略图地址',
})
wechat.invoke('scanQRCode').then(res => {
  // => API 调用结果
})

XUrl

源码 | API | 回目录

将 File 转换为字符串。

📦 工具类型

AnyFunction

源码 | API | 回目录

任意函数类型。

AnyObject

源码 | API | 回目录

任意对象类型。

AsyncOrSync

源码 | API | 回目录

// before
type X = PromiseLike<string> | string
// after
type X = AsyncOrSync<string>

AsyncReturnType

源码 | API | 回目录

类似 ReturnType,不过会返回 Promise<R> 中的 R

type Result0 = ReturnType<() => Promise<number>> // => Promise<number>
type Result1 = AsyncReturnType<() => Promise<number>> // => number

Brand

源码 | API | 回目录

名义化类型。

type User = { id: Brand<number, User>, name: string }
type Post = { id: Brand<number, Post>, title: string }
type UserIdIsNumber = User['id'] extends number ? true: false // => true
type PostIdIsNumber = Post['id'] extends number ? true: false // => true
type PostIdIsNotUserId = Post['id'] extends User['id'] ? false : true // => true

Defined

源码 | API | 回目录

T 中排除 undefined 类型。

interface User {
  gender?: 'male' | 'female',
}
// before
type UserGender = Exclude<User['gender'], undefined>
// after
type UserGender = Defined<User['gender']>

If

源码 | API | 回目录

条件类型。

type X = 'x'
// before
type IsX = X extends 'x' ? true : false
// after
type IsX = If<X extends 'x', true, false>

IsNever

源码 | API | 回目录

检查 T 是否是 never 类型。

type X = never
// before
type XIsNever = [X] extends [never] ? true : false
// after
type XIsNever = IsNever<X>

LiteralUnion

源码 | API | 回目录

字面量联合类型。

// before: China, American 将得不到类型提示
type Country = 'China' | 'American' | string
// after: China, American 将得到类型提示
type Country = LiteralUnion<'China' | 'American', string>

Merge

源码 | API | 回目录

合并两个类型,后一个类型的定义将覆盖前一个类型的定义。

type X = Merge<
  { x: number, y: number },
  { x: string, z: string }
>
// => { x: string, y: number, z: string }

Omit

源码 | API | 回目录

从接口 T 中去除指定的属性。

type X = Omit<
  { x: number, y: string, z: boolean },
  'x' | 'z'
>
// => { y: string }

OneOrMore

源码 | API | 回目录

// before
type X = number | number[]
// after
type X = OneOrMore<number>

PartialBy

源码 | API | 回目录

T 中的 K 可选。

interface User {
  id: number,
  age: number,
}
type UserWithOptionalAge = PartialBy<User, 'age'>
// type UserWithOptionalAge = {
//   id: number,
//   age?: number,
// }

RequiredBy

源码 | API | 回目录

T 中的 K 必填。

interface UserWithOptionalAge {
  id: number,
  age?: number,
}
type User = RequiredBy<UserWithOptionalAge, 'age'>
// type User = {
//   id: number,
//   age: number,
// }

ValueOf

源码 | API | 回目录

返回接口 T 属性值的类型。

type V = ValueOf<{ x: number, y: string, z: boolean }>
// => number | string | boolean

许可

MIT ©️ Jay Fong

You can’t perform that action at this time.