967 lines
22 KiB
TypeScript
967 lines
22 KiB
TypeScript
/**
|
||
* 对数字进行补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`直接,包含min,max
|
||
* 即:[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)
|
||
},
|
||
},
|
||
})
|