https://fjc0k.github.io/vtils/
# yarn
yarn add vtils
# or, npm
npm i vtils --save
在线体验:https://stackblitz.com/edit/vtils
import { inBrowser,shuffle } from 'vtils'
if (inBrowser()) {
alert('您在浏览器中...')
}
alert(shuffle([1, 2, 3, 4]))
分配来源对象的可枚举属性到目标对象上。
来源对象的应用规则是从左到右,随后的下一个对象的属性会覆盖上一个对象的属性。
assign(
{},
{ x: 1 },
{ y: 2 },
{ x: 5, z: 9 },
)
// => { x: 5, y: 2, z: 9 }
返回 base64
解码后的字符串。
base64Decode('dnRpbHM=') // => vtils
base64Decode('5Lit5Zu9') // => 中国
base64Decode('8J+RqOKAjfCfkrs=') // => 👨💻
返回 base64
编码后的字符串。
base64Encode('vtils') // => dnRpbHM=
base64Encode('中国') // => 5Lit5Zu9
base64Encode('👨💻') // => 8J+RqOKAjfCfkrs=
返回 base64url
解码后的字符串。
base64Decode('dnRpbHM=') // => vtils
base64Decode('5Lit5Zu9') // => 中国
base64Decode('8J-RqOKAjfCfkrs=') // => 👨💻
返回 base64url
编码后的字符串。
base64UrlEncode('vtils') // => dnRpbHM=
base64UrlEncode('中国') // => 5Lit5Zu9
base64UrlEncode('👨💻') // => 8J-RqOKAjfCfkrs=
如果 value
是数组,直接返回;如果 value
不是数组,返回 [value]
。
castArray([123, 456]) // => [123, 456]
castArray(123) // => [123]
castArray('hello') // => ['hello']
castArray(null) // => [null]
将 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(50, 0, 100) // => 50
clamp(50, 0, 50) // => 50
clamp(50, 0, 49) // => 49
clamp(50, 51, 100) // => 51
检查 str
是否以 needle
结尾。
endsWith('hello', 'llo') // => true
endsWith('hello', 'he') // => false
使用 value
来填充(替换) arr
,从 start
位置开始, 到 end
位置结束(但不包括 end
位置)。
fill(Array(5), () => 1) // => [1, 1, 1, 1, 1]
fill(Array(3), (value, index) => index) // => [0, 1, 2]
移动端屏幕适配。
遍历对象的可枚举属性。若遍历函数返回 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() // => window
// Node 中
getGlobal() // => global
检测 value
的类型。
getType(1) // => Number
getType(true) // => Boolean
getType([]) // => Array
getType(/hello/) // => RegExp
根据 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: '花生' },
// => ],
// => }
检查 key
是否是对象 obj
自身的属性。
const obj = { x: 1, 2: 'y' }
has(obj, 'x') // => true
has(obj, 2) // => true
has(obj, 'toString') // => false
立即调用函数并返回其返回值。
注:ii = immediately invoke
ii(() => 1) // => 1
检查是否在 Android
设备中。
// Android 设备中
inAndroid() // => true
inAndroid(
() => console.log('你在 Android 设备中'),
)
检查是否在浏览器环境中。
// 浏览器中
inBrowser() // => true
inBrowser(
() => console.log('你在浏览器中'),
)
检查是否在 iOS
设备中。
// iOS 设备中
inIOS() // => true
inIOS(
() => console.log('你在 iOS 设备中'),
)
检查是否在 Node
环境中。
// Node 中
inNode() // => true
inNode(
() => console.log('你在 Node 中'),
)
检查 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() // => true
inWechatMiniProgram(
() => console.log('你在微信小程序中'),
)
检查是否在微信浏览器环境中。
// 微信浏览器中
inWechatWebview() // => true
inWechatWebview(
() => console.log('你在微信浏览器中'),
)
检索值 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
检查 value
是否是一个数组。
isArray(['x']) // => true
isArray('x') // => false
检查 value
是否是一个布尔值。
isBoolean(true) // => true
isBoolean(false) // => true
isBoolean('true') // => false
检查 value
是否是合法的中国大陆居民 18
位身份证号码。
isChineseIDCardNumber('123456') // => false
检查 value
是否是一个日期。
isDate(new Date()) // => true
检查 value
是否是一个邮件地址。
isEmail('hello@foo.bar') // => true
isEmail('hello@foo') // => false
检查 value
是否是空值,包括:undefined
、null
、''
、false
、true
、[]
、{}
。
isEmpty(undefined) // => true
isEmpty(null) // => true
isEmpty('') // => true
isEmpty(false) // => true
isEmpty(true) // => true
isEmpty([]) // => true
isEmpty({}) // => true
检查给定的数组的各项是否相等。
isEqualArray([1], [1]) // => true
isEqualArray([1], [5]) // => false
检查 value
是否是原始有限数值。
isFinite(1) // => true
isFinite(Infinity) // => false
检查 value
是否是一个函数。
isFunction(() => {}) // => true
isFunction(2000) // => false
检查 value
是否全是汉字。
isHan('hello') // => false
isHan('嗨咯') // => true
检查 value
是否是一个整数。
isInteger(1) // => true
isInteger(1.2) // => false
isInteger(-1) // => true
检查 value
是否是 NaN
。
isNaN(NaN) // => true
isNaN(2) // => false
检查 value
是否是一个负整数。
isNegativeInteger(-1) // => true
isNegativeInteger(1) // => false
检查 value
是否是 null
或 undefined
。
isNil(null) // => true
isNil(undefined) // => true
检查 value
是否是 null
。
isNull(null) // => true
检查 value
是否是一个数字。
注:NaN
不被认为是数字。
isNumber(1) // => true
isNumber(0.1) // => true
isNumber(NaN) // => false
检查 value
是否是一个数值。
注:Infinity
、-Infinity
、NaN
不被认为是数值。
isNumeric(1) // => true
isNumeric('1') // => true
检查 value
是否是一个对象。
isObject({}) // => true
isObject(() => {}) // => true
isObject(null) // => false
检查 value
是否是一个普通对象。
isPlainObject({}) // => true
isPlainObject(Object.create(null)) // => true
isPlainObject(() => {}) // => false
检查 value
是否是一个正整数。
isPositiveInteger(1) // => true
isPositiveInteger(-1) // => false
检测 number
是否可能是中国的手机号码。
isPossibleChineseMobilePhoneNumber(18000030000) // => true
isPossibleChineseMobilePhoneNumber(10086) // => false
检测 value
是否可能是中国人的姓名,支持少数名族姓名中间的 ·
号。
isPossibleChineseName('鲁') // => false
isPossibleChineseName('鲁迅') // => true
isPossibleChineseName('买买提·吐尔逊') // => true
检查 value
是否像 Promise
。
isPromiseLike(Promise.resolve()) // => true
检查 value
是否是一个正则对象。
isRegExp(/hello/) // => true
isRegExp(new RegExp('hello')) // => true
检查 value
是否是一个字符串。
isString('') // => true
isString('hello') // => true
检查 value
是否等于 undefined
。
isUndefined(undefined) // => true
isUndefined(void 0) // => true
检查 value
是否是一个有效的网址,仅支持 http
、https
协议,支持 IP
域名。
isUrl('http://foo.bar') // => true
isUrl('https://foo.bar/home') // => true
根据 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: '花生' },
// => }
返回 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']
返回数组 arr
的最后一项。
last([1, 2, 3]) // => 3
加载图片、代码、样式等资源。
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(() => {
// 资源加载完成后的操作
})
映射对象的可枚举属性值为一个新的值。
mapValues(
{ x: 1, y: 2 },
value => value + 10,
)
// => { x: 11, y: 12 }
函数结果缓存。
let i = 0
const fn = memoize(() => i++)
fn() // => 0
fn() // => 0
无操作函数。
noop() // => undefined
创建一个从 obj
中剔除选中的可枚举属性的对象。
omit({ x: 1, y: 2 }, ['x']) // => { y: 2 }
在 str
右侧填充字符。
padEnd('姓名', 4, '*') // => 姓名**
在 str
左侧填充字符。
padStart('姓名', 4, '*') // => **姓名
并行执行任务,同步任务
、异步任务
皆可。
parallel([
() => 1,
async () => 'hello',
]).then(res => {
// => [1, 'hello']
})
解析 CSS
值的数值和单位。
parseCSSValue('12px') // => { value: 12, unit: 'px' }
parseCSSValue(12) // => { value: 12, unit: 'px' }
parseCSSValue('12%') // => { value: 12, unit: '%' }
创建一个从 obj
中选中的可枚举属性的对象。
pick({ x: 1, y: 2 }, ['x']) // => { x: 1 }
给定大小获取占位猫咪图片,图片来自:https://placekitten.com/
placeKitten(100) // => https://placekitten.com/100/100
给定宽高获取占位猫咪图片,图片来自:https://placekitten.com/
placeKitten(100, 200) // => https://placekitten.com/100/200
生成一个随机字符串。
randomString() // => m481rnmse1m
创建一个包含从 start
到 end
,但不包含 end
本身范围数字的数组。
range(0, 5) // => [0, 1, 2, 3, 4]
range(0, -5, -1) // => [0, -1, -2, -3, -4]
重复 n
次给定字符串。
repeat('a', 5) // => aaaaa
对传入的数字按给定的精度四舍五入后返回。
round(3.456) // => 3
round(3.456, 1) // => 3.5
round(3.456, 2) // => 3.46
round(345, -2) // => 300
对传入的数字按给定的精度向下取值后返回。
roundDown(3.456) // => 3
roundDown(3.456, 1) // => 3.4
roundDown(3.456, 2) // => 3.45
roundDown(345, -2) // => 300
对传入的数字按给定的精度向上取值后返回。
roundUp(3.456) // => 4
roundUp(3.456, 1) // => 3.5
roundUp(3.456, 2) // => 3.46
roundUp(345, -2) // => 400
从数组中随机获取一个元素。
sample([1, 2, 3]) // => 1 或 2 或 3
从对象中随机获取一个可枚举属性的值。
sample({ x: 1, y: 2, z: 3 }) // => 1 或 2 或 3
顺序执行任务,同步任务
、异步任务
皆可。
sequential([
() => 1,
async () => 'hello',
]).then(res => {
// => [1, 'hello']
})
打乱一个数组。
shuffle([1, 2]) // => [1, 2] 或 [2, 1]
检查 str
是否以 needle
开头。
startsWith('hello', 'he') // => true
startsWith('hello', 'llo') // => false
计算传入值的总和。
sum([1, 2, 3]) // => 6
根据 iteratee
返回的结果计算传入值的总和。
sumBy(
[
{ count: 1 },
{ count: 2 },
{ count: 3 },
],
item => item.count,
)
// => 6
调用函数 n
次,将每次的调用结果存进数组并返回。
times(4, () => {
// 这里将会执行 4 次
})
返回 obj
自身可枚举属性值组成的数组。
values({ x: 1, 2: 'y' }) // => [1, 'y'] 或 ['y', 1]
等待一段时间。
wait(1000).then(() => {
// 等待 1000 毫秒后执行
})
资源释放器。
const disposer = new Disposer()
const timer = setInterval(
() => console.log('ok'),
1000,
)
disposer.add(() => clearInterval(timer))
document.querySelector('#stop').onclick = () => {
disposer.dispose()
}
微信小程序 Storage
适配器。
由于微信小程序的 wx.getStorageSync
方法对于不存在的项目会返回 空字符串
,导致无法判断项目是否存在,因此,该适配器对存储的内容做了一层封装,以保证相关操作的结果可确定。
数据对象验证器。
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, unvalidRules: [{ key: 'pass2', test: ({ pass1, pass2 }) => pass2 === pass1, message: '两次密码应一致' }] }
})
事件巴士,管理事件的发布与订阅。
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')
对微信 JSSDK 的封装。
const wechat = new Wechat()
getWechatConfigAsync().then(config => {
wechat.config(config)
})
wechat.updateShareData({
title: '分享标题',
desc: '分享描述',
link: '分享链接',
imgUrl: '缩略图地址',
})
wechat.invoke('scanQRCode').then(res => {
// => API 调用结果
})
从 T
中排除 undefined
类型。
interface User {
gender?: 'male' | 'female',
}
// before
type UserGender = Exclude<User['gender'], undefined>
// after
type UserGender = Defined<User['gender']>
条件类型。
type X = 'x'
// before
type IsX = X extends 'x' ? true : false
// after
type IsX = If<X extends 'x', true, false>
MIT ©️ Jay Fong
© 2010 - cnpmjs.org x YWFE | Home | YWFE