2023-06-12 16:42:07 +08:00

967 lines
22 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 对数字进行补0操作
* @param value 要补0的数值
* @param length 要补的总长度
* @return 补0之后的字符串
*/
function zeroize(value: number | string, length: number = 2): string {
let str = '' + value
let zeros = ''
for (let i = 0, len = length - str.length; i < len; i++) {
zeros += '0'
}
return zeros + str
}
/****************************************扩展Object****************************************/
interface Object {
/**
* 返回一个浅副本的对象
* 此对象会拷贝key value
*
* @memberOf Object
*/
clone?(): Object
/**
* 将数据拷贝到 to
* @param to 目标
*/
copyto?(to: Object): void
/**
* 获取指定属性的描述,会查找当前数据和原型数据
* @param property 指定的属性名字
*/
getPropertyDescriptor?(property: string): PropertyDescriptor
zssign?(target: any): any
}
Object.defineProperties(Object.prototype, {
clone: {
value: function () {
let o = {}
for (let n in this) {
// @ts-ignore
o[n] = this[n]
}
return o
},
writable: true,
},
getPropertyDescriptor: {
value: function (property: string): any {
let data = Object.getOwnPropertyDescriptor(this, property)
if (data) {
return data
}
let prototype = Object.getPrototypeOf(this)
if (prototype) {
return prototype.getPropertyDescriptor(property)
}
return
},
writable: true,
},
copyto: {
value: function (to: Object) {
for (let p in this) {
if (!(p in to)) {
// 本身没有这个属性
// @ts-ignore
to[p] = this[p]
} else {
let data: PropertyDescriptor = to.getPropertyDescriptor(p)
if (data) {
if (data.set || data.writable) {
// 可进行赋值
// @ts-ignore
to[p] = this[p]
}
}
}
}
},
writable: true,
},
zssign: {
value: function (target: Object) {
if (target === undefined || target === null) {
throw new TypeError('Cannot convert undefined or null to object')
}
let output = Object(target)
for (let nextKey in this) {
if (!(nextKey in output)) {
// 本身没有这个属性
output[nextKey] = this[nextKey]
}
// else {
// let data: PropertyDescriptor = output.getPropertyDescriptor(nextKey);
// if (data) {
// if (data.set || data.writable) {// 可进行赋值
// output[nextKey] = this[nextKey];
// }
// }
// }
}
return output
},
writable: true,
},
})
/****************************************扩展Math****************************************/
interface Math {
/**
* 角度转弧度的乘数
* Math.PI / 180
* @type {number}
* @memberOf Math
*/
DEG_TO_RAD: number
/**
* 弧度转角度的乘数
* 180 / Math.PI
*/
RAD_TO_DEG: number
/**
* 整圆的弧度
*/
PI2: number
/**
* 90°的弧度
*
* @type {number}
* @memberOf Math
*/
PI_1_2: number
/**
* 让数值处于指定的最大值和最小值之间,低于最小值取最小值,高于最大值取最大值
* @param value 要处理的数值
* @param min 最小值
* @param max 最大值
*/
clamp?(value: number, min: number, max: number): number
/**
* 从最小值到最大值之间随机[min,max)
*/
random2?(min: number, max: number): number
}
Math.DEG_TO_RAD = Math.PI / 180
Math.RAD_TO_DEG = 180 / Math.PI
Math.PI2 = 2 * Math.PI
Math.PI_1_2 = Math.PI * 0.5
Math.clamp = (value, min, max) => {
if (value < min) {
value = min
}
if (value > max) {
value = max
}
return value
}
Math.random2 = (min, max) => {
return min + Math.random() * (max - min)
}
/****************************************扩展Number********************************************/
interface Number {
/**
* 对数字进行补0操作
* @param length 要补的总长度
* @return 补0之后的字符串
*/
zeroize?(length: number): string
/**
* 数值介于,`min` `max`直接包含minmax
* 即:[min,max]
*
* @param {number} min
* @param {number} max
* @returns {boolean}
*/
between?(min: number, max: number): boolean
}
Object.defineProperties(Number.prototype, {
zeroize: {
value: function (this: number, length: number) {
return zeroize(this, length)
},
writable: true,
},
between: {
value: function (this: number, min: number, max: number) {
return min <= this && max >= this
},
writable: true,
},
})
/****************************************扩展String****************************************/
interface String {
/**
* 替换字符串中{0}{1}{2}{a} {b}这样的数据用obj对应key替换或者是数组中对应key的数据替换
*/
substitute?(args: any[]): string
/**
* 对数字进行补0操作
* @param length 要补的总长度
* @return 补0之后的字符串
*/
zeroize?(length: number): string
/**
* 将一个字符串转换成一个很小几率重复的数值
* <font color="#ff0000">此方法hash的字符串并不一定唯一慎用</font>
*/
hash?(): number
/**
* 获取字符串长度,中文方块字符算两个长度
*/
trueLength?(): number
/**
* 中文字符个数
* */
cnLength?(): number
/**
* 比较版本号
* */
versionCompare?(target: string): number
}
Object.defineProperties(String.prototype, {
zeroize: {
value: function (length: number) {
return zeroize(this, length)
},
writable: true,
},
substitute: {
value: function (this: string) {
let len = arguments.length
if (len > 0) {
let obj: IArguments
if (len == 1) {
obj = arguments[0]
if (typeof obj !== 'object') {
obj = arguments
}
} else {
obj = arguments
}
if (obj instanceof Object && !(obj instanceof RegExp)) {
return this.replace(/\{(?:%([^{}]+)%)?([^{}]+)\}/g, function (match: string, handler: string, key: string) {
//检查key中是否为%开头,如果是,则尝试按方法处理
// @ts-ignore
let value = obj[key]
if (handler) {
//如果有处理器,拆分处理器
let func = String.subHandler[handler]
if (func) {
value = func(value)
}
}
return value !== undefined ? '' + value : match
})
}
}
return this.toString() //防止生成String对象ios反射String对象会当成一个NSDictionary处理
},
writable: true,
},
hash: {
value: function () {
let len = this.length
let hash = 5381
for (let i = 0; i < len; i++) {
hash += (hash << 5) + this.charCodeAt(i)
}
return hash & 0x7fffffff
},
writable: true,
},
trueLength: {
value: function () {
let arr: string[] = this.match(/[^x00-xff]/gi)
return this.length + (arr ? arr.length : 0)
},
writable: true,
},
cnLength: {
value: function () {
// /[\u2E80-\u9FBF]
let arr: string[] = this.match(/[^x00-xff]/gi)
return arr ? arr.length : 0
},
writable: true,
},
versionCompare: {
value: function (target: string): number {
const GTR = 1 //大于
const LSS = -1 //小于
const EQU = 0 //等于
if (!target) {
return GTR
}
let v1arr = String(this)
.split('.')
.map(function (a) {
return parseInt(a)
})
let v2arr = String(target)
.split('.')
.map(function (a) {
return parseInt(a)
})
let arrLen = Math.max(v1arr.length, v2arr.length)
let result
//排除错误调用
if (this == undefined || target == undefined) {
throw new Error()
}
//检查空字符串,任何非空字符串都大于空字符串
if (this.length == 0 && target.length == 0) {
return EQU
} else if (this.length == 0) {
return LSS
} else if (target.length == 0) {
return GTR
}
//循环比较版本号
for (let i = 0; i < arrLen; i++) {
result = versionComp(v1arr[i], v2arr[i])
if (result == EQU) {
continue
} else {
break
}
}
return result
function versionComp(n1: number, n2: number) {
if (typeof n1 != 'number') {
n1 = 0
}
if (typeof n2 != 'number') {
n2 = 0
}
if (n1 > n2) {
return GTR
} else if (n1 < n2) {
return LSS
} else {
return EQU
}
}
},
writable: true,
},
})
interface StringConstructor {
/**
* 对数字进行补0操作
* @param value 要补0的数值
* @param length 要补的总长度
* @return 补0之后的字符串
*/
zeroize?: (value: number, length: number) => string
/**
* substitute的回调函数
*
* @type {Readonly<{ [index: string]: { (input: any): string } }>}
* @memberOf StringConstructor
*/
subHandler?: Readonly<{ [index: string]: { (input: any): string } }>
}
String.zeroize = zeroize
/****************************************扩展Date****************************************/
interface Date {
/**
* 格式化日期
*
* @param {string} mask 时间字符串
* @param {boolean} [local] 是否基于本地时间显示目前项目除了报错信息其他时间都用UTC时间显示
* @returns {string} 格式化后的时间
*/
format(mask: string, local?: boolean): string
/**
* 增加n天
* @param {number} days
* @return {Date}
*/
addDays(days: number): Date
}
Object.defineProperties(Date.prototype, {
format: {
value: function (mask: string, local?: boolean) {
let d: Date = this
// @ts-ignore
return mask.replace(/"[^"]*"|'[^']*'|(?:d{1,2}|m{1,2}|yy(?:yy)?|([hHMs])\1?)/g, function ($0: string) {
switch ($0) {
case 'd':
return gd()
case 'dd':
return zeroize(gd())
case 'M':
return gM() + 1
case 'MM':
return zeroize(gM() + 1)
case 'yy':
return (gy() + '').substr(2)
case 'yyyy':
return gy()
case 'h':
return gH() % 12 || 12
case 'hh':
return zeroize(gH() % 12 || 12)
case 'H':
return gH()
case 'HH':
return zeroize(gH())
case 'm':
return gm()
case 'mm':
return zeroize(gm())
case 's':
return gs()
case 'ss':
return zeroize(gs())
default:
return $0.substr(1, $0.length - 2)
}
})
function gd() {
return local ? d.getDate() : d.getUTCDate()
}
function gM() {
return local ? d.getMonth() : d.getUTCMonth()
}
function gy() {
return local ? d.getFullYear() : d.getUTCFullYear()
}
function gH() {
return local ? d.getHours() : d.getUTCHours()
}
function gm() {
return local ? d.getMinutes() : d.getUTCMinutes()
}
function gs() {
return local ? d.getSeconds() : d.getUTCSeconds()
}
},
writable: true,
},
addDays: {
value: function (days: number) {
this.setDate(this.getDate() + days)
return this
},
writable: true,
},
})
/****************************************扩展Array****************************************/
const enum ArraySort {
/**
* 升序
*/
ASC = 0,
/**
* 降序
*/
DESC = 1,
}
interface ArrayConstructor {
// binaryInsert<T>(partArr: T[], item: T, filter: { (tester: T, ...args): boolean }, ...args);
SORT_DEFAULT: { number: 0; string: ''; boolean: false }
}
/**
* 用于对Array排序时处理undefined
*/
Array.SORT_DEFAULT = {
number: 0,
string: '',
boolean: false,
}
Object.freeze(Array.SORT_DEFAULT)
interface Array<T> {
/**
* 如果数组中没有要放入的对象,则将对象放入数组
*
* @param {T} t 要放入的对象
* @returns {number} 放入的对象,在数组中的索引
*
* @member Array
*/
pushOnce?(t: T): number
/**
*
* 删除某个数据
* @param {T} t
* @returns {boolean} true 有这个数据并且删除成功
* false 没有这个数据
*/
zremove?(t: T): boolean
/**
* 排序 支持多重排序
* 降序, 升序
* @param {(keyof T)[]} kArr 参数属性列表
* @param {(boolean[] | ArraySort[])} [dArr] 是否降序,默认升序
* @returns {this}
*
* @member Array
*/
multiSort?(kArr: (keyof T)[], dArr?: boolean[] | ArraySort[]): this
/**
* 默认排序
*
* @param {string} [key]
* @param {boolean} [descend]
*
* @member Array
*/
doSort?(key?: keyof T, descend?: boolean | ArraySort): this
doSort?(descend?: boolean | ArraySort, key?: keyof T): this
/**
* 将数组克隆到to
* to的数组长度会和当前数组一致
*
* @template T
* @param {Array<T>} to
*/
cloneTo?<T>(to: Array<T>): void
/**
* 将数组附加到to中
*
* @template T
* @param {Array<T>} to
*
* @member ArrayConstructor
*/
appendTo?<T>(to: Array<T>): void
/**
* 移除数组index位置的元素, 比slice效率高
* @param index
*/
spliceOne?(index: number): boolean
/**
* 随机排序
*/
randomSort?(): void
/**
* 检查数组中是否含有另外一个object
* @param obj 与数组同类型的obj | 同类型的数组 | 指定child字段的值 | 指定child字段的数组
* @param child 比较字段
*/
contains?<T>(obj: T | T[] | {} | {}[], child?: string): boolean
/**
* 将数组随机插入当前数组中
* @param arr
*/
randomInsert?<T>(arr: Array<T>): void
/**
* 随机获取n个元素
* @param count
*/
randomGet?<T>(count?: number): T[]
/**
* 随机获取1个元素
*/
randomOne?<T>(): T
/**
* 随机移除n个元素
* @param count
*/
randomRemove?<T>(count?: number): T[]
/**
* 数组移动n位
* @param n n > 0 右移, n<0 左移
*/
moveElement?<T>(n: number): T[]
/**
* 两个数组并集
* @param arr
*/
union?<T>(arr: T[]): T[]
/**
* 两个数组交集
* @param arr
*/
intersect?<T>(arr: T[]): T[]
/**
* 相对于arr的差集
* @param arr
*/
difference?<T>(arr: T[]): T[]
/**
* 转换成Map
* @param {string} key 用于生成map的key字段名
* @return {Map<any, T>}
*/
toMap?<T>(key: string): Map<any, T>
}
Object.defineProperties(Array.prototype, {
cloneTo: {
value: function <T>(this: T[], b: any[]) {
b.length = this.length
let len = this.length
b.length = len
for (let i = 0; i < len; i++) {
b[i] = this[i]
}
},
writable: true,
},
appendTo: {
value: function <T>(this: T[], b: any[]) {
let len = this.length
for (let i = 0; i < len; i++) {
b.push(this[i])
}
},
writable: true,
},
pushOnce: {
value: function <T>(this: T[], t: T) {
let idx = this.indexOf(t)
if (!~idx) {
idx = this.length
this.push(t)
}
return idx
},
writable: true,
},
zremove: {
value: function <T>(this: T[], t: T) {
let idx = this.indexOf(t)
if (~idx) {
this.splice(idx, 1)
return true
}
return false
},
writable: true,
},
doSort: {
value: function () {
let key: string, descend: boolean
let len = arguments.length
for (let i = 0; i < len; i++) {
let arg = arguments[i]
let t = typeof arg
if (t === 'string') {
key = arg
} else {
descend = !!arg
}
}
if (key) {
return this.sort((a: any, b: any) => (descend ? b[key] - a[key] : a[key] - b[key]))
} else {
return this.sort((a: any, b: any) => (descend ? b - a : a - b))
}
},
writable: true,
},
multiSort: {
value: function (kArr: string[], dArr?: boolean[] | boolean) {
let isArr = Array.isArray(dArr)
return this.sort((a: any, b: any): number => {
const def = Array.SORT_DEFAULT
for (let idx = 0, len = kArr.length; idx < len; idx++) {
let key = kArr[idx]
// @ts-ignore
let mode = isArr ? !!dArr[idx] : !!dArr
let av = a[key]
let bv = b[key]
let typea = typeof av
let typeb = typeof bv
if (typea == 'object' || typeb == 'object') {
return 0
} else if (typea != typeb) {
if (typea == 'undefined') {
// @ts-ignore
bv = def[typeb]
} else if (typeb == 'undefined') {
// @ts-ignore
av = def[typea]
} else {
return 0
}
}
if (av < bv) {
return mode ? 1 : -1
} else if (av > bv) {
return mode ? -1 : 1
} else {
continue
}
}
return 0
})
},
writable: true,
},
spliceOne: {
value: function (index: number): boolean {
if (index === -1 || index >= this.length) {
return false
}
const len = this.length - 1
for (let i = index; i < len; i++) {
this[i] = this[i + 1]
}
this.length = len
return true
},
writable: true,
},
randomSort: {
value: function <T>() {
for (let j, x, i = this.length; i; j = (Math.random() * i) | 0, x = this[--i], this[i] = this[j], this[j] = x) {}
},
writable: true,
},
contains: {
value: function <T>(obj: T | T[] | {} | {}[], child?: string): boolean {
let result = false
if (child) {
const isArr = Array.isArray(obj)
if (isArr) {
// @ts-ignore
if (obj[0].hasOwnProperty(child)) {
let set0 = new Set()
// @ts-ignore
for (let s of obj) {
// @ts-ignore
set0.add(s[child])
}
// @ts-ignore
let set1 = new Set(this.filter(x => set0.has(x)))
return set0.size === set1.size
} else {
// @ts-ignore
let set0 = new Set(obj)
let set1 = new Set(this.filter((x: {}) => set0.has(x)))
return set1.size === set0.size
}
} else {
if (obj.hasOwnProperty(child)) {
for (let sub of this) {
if (sub.hasOwnProperty(child)) {
// @ts-ignore
if (sub[child] === obj[child]) {
result = true
break
}
}
}
} else {
for (let sub of this) {
if (sub.hasOwnProperty(child)) {
// @ts-ignore
if (sub[child] === obj) {
result = true
break
}
}
}
}
}
} else {
// 不指定 比较字段 的话, 只处理2种情况
// 1: obj 为数组
// 2: obj 不是数组
if (Array.isArray(obj)) {
let set0 = new Set(obj)
// @ts-ignore
let set1 = new Set(this.filter(x => set0.has(x)))
return set1.size === set0.size
} else {
let idx = this.indexOf(obj)
return !!~idx
}
}
return result
},
writable: true,
},
randomInsert: {
value: function <T>(arr: Array<T>) {
const length = this.length
arr.forEach(value => {
this.splice(Math.random() * length, 0, value)
})
},
writable: true,
},
randomGet: {
value: function <T>(count: number = 1): T[] {
let shuffled: T[] = this.slice(0),
i = this.length,
min = i - count,
temp,
index
if (min < 0) {
return shuffled
}
while (i-- > min) {
index = Math.floor((i + 1) * Math.random())
temp = shuffled[index]
shuffled[index] = shuffled[i]
shuffled[i] = temp
}
return shuffled.slice(min)
},
writable: true,
},
randomOne: {
value: function <T>(): T {
let results = this.randomGet(1)
if (results.length > 0) {
return results[0]
} else {
return null
}
},
writable: true,
},
randomRemove: {
value: function <T>(count: number = 1): T[] {
let result = []
while (count-- > 0 && this.length > 0) {
let index = (Math.random() * this.length) | 0
result.push(...this.splice(index, 1))
}
return result
},
writable: true,
},
moveElement: {
value: function <T>(n: number): T[] {
if (Math.abs(n) > this.length) n = n % this.length
return this.slice(-n).concat(this.slice(0, -n))
},
writable: true,
},
union: {
value: function <T>(this: T[], b: any[]): T[] {
let a = this.concat(b)
return [...new Set(a)]
},
writable: true,
},
intersect: {
value: function <T>(this: T[], b: any[]): T[] {
let set0 = new Set(b)
let set1 = new Set(this.filter(x => set0.has(x)))
return [...set1]
},
writable: true,
},
difference: {
value: function <T>(this: T[], b: any[]): T[] {
let set0 = new Set(b)
let set1 = new Set(this.filter(x => !set0.has(x)))
return [...set1]
},
writable: true,
},
toMap: {
value: function <T>(this: T[], key: string) {
let result: Map<any, T> = new Map()
for (const o of this) {
// @ts-ignore
result.set(o[key], o)
}
return result
},
writable: true,
},
})
interface Map<K, V> {
/**
* 只针对V为number的Map, 有值的话, 加上V, 没值则直接set
* V为其他类型时, 直接set
* @param key
* @param value
*/
inc?(key: K, value: V): number
}
Object.defineProperties(Map.prototype, {
inc: {
value: function <K, V>(key: K, value: V) {
if (typeof value == 'number') {
this.set(key, (this.get(key) || 0) + value)
} else {
this.set(key, value)
}
return this.get(key)
},
},
})