Xiaobing's Blog

10%
  • 1
下午好!
23.43K

Typography and Codes

hello
预计阅读时间:77分钟
Accordion_first_title
No choice
TypeScript
export const isRegExp = (arg: unknown): arg is RegExp = Object.prototype.toString.call(arg) === "[object RegExp]"
Hello, world

查看被占用端口:

netstat -aon | findstr 8080

查看被占用端口PID:

tasklist | findstr 88888

杀掉进程:

tasklist /f /PID 88888


检查两个数组对象是否相同

实现函数

function equalsObj(oldData: any, newData: any): boolean {
  if (oldData === newData)
    return true

  if (isObject(oldData) && isObject(newData) && Object.keys(oldData).length === Object.keys(newData).length) {
    for (const key in oldData) {
      if (oldData.hasOwnProperty(key)) {
        if (!equalsObj(oldData[key], newData[key]))
          return false
      }
    }
  }
  else if (isArray(oldData) && isArray(newData) && oldData.length === newData.length) {
    for (let i = 0, length = oldData.length; i < length; i++) {
      if (!equalsObj(oldData[i], newData[i]))
        return false
    }
  }
  else {
    return false
  }
  return true
}

测试:

const arr1: (Record<string, any> | string)[] = [{ id: 1, name: '嘿嘿', go: 'xi', child: { id: 55 }, is: 2 }, 'hh']
const arr2: (Record<string, any> | string)[] = [{ id: 1, name: '嘿嘿', go: 'xi', child: { id: 55 }, is: 2 }, 'hh']

console.log(equalsObj(arr1, arr2))
console.log(equalsObj(JSON.stringify(arr1), JSON.stringify(arr2)))

工具函数:


export const isString = (arg: unknown): arg is string => typeof arg == 'string'
export const isArray = <T>(arg: unknown): arg is T[] => Array.isArray(arg) && typeof arg == 'object'
export const isNumber = (arg: unknown): arg is number => !Number.isNaN(Number(arg))
export const isFunction = (arg: unknown): arg is () => void => typeof arg === 'function'
export const isObject = (arg: unknown): arg is Record<any, any> => arg !== null && typeof arg === 'object'
export const isRegExp = (arg: unknown): arg is RegExp => Object.prototype.toString.call(arg) === '[object RegExp]'
export function isPromise<T = any>(arg: unknown): arg is Promise<T> {
  return (
    (isObject(arg) || isFunction(arg))
    && isFunction((arg as any).then)
    && isFunction((arg as any).catch)
  )
}

其他工具

'use strict'

export namespace UseModels {
  type ModelParams<T extends ModelPathType> = typeof ALL_MODELS_PARAMS[T]
  type ModelParamsKey<T extends ModelPathType> = keyof ModelParams<T>
  type ModelParamsWithIndexSignature<T extends ModelPathType> = ModelParams<T> & {
    [key: string]: AvailableValue
  }
  type FnKeepsakeKeyType<T extends ModelPathType> = ModelParamsKey<T>
  type AvailableValue = number | string
  type FetchReturnType<T extends ModelPathType, U extends ModelParamsKey<T> | ModelParamsKey<T>[] | [], SimpleType> =
    U extends ModelParamsKey<T>[] | []
      ? { [P in (U extends [] ? ModelParamsKey<T>[] : U)[number]]: AvailableValue }
      : SimpleType
  type ModelObjectsKeyType = ModelParamsWithIndexSignature<ModelPathType>
  type SubclassKeyType = typeof SUBCLASS[number]
  type ReassignObjectReturnType = Record<keyof ModelObjectsKeyType, AvailableValue>

  export declare namespace MultiCategoryScreening {
    export type SelectionType = number | number[]
    export interface SubclassArraysType {
      key: SubclassKeyType
      preselectionValues: SelectionType
      alreadySelectValues: SelectionType
    }

    export interface ReturnType {
      url: string
      subclassArrays: SubclassArraysType[]
    }

    export interface TransferType {
      id: number
      subclass: SubclassKeyType
      type: ModelPathType
      maxLength: number
      pathname: string
      firstID?: number
      keyword?: AvailableValue | null
    }
  }

  export interface UtilsInterface {
    readonly MULTI_CATEGORY_SEPARATOR: string
    joinObjectValues: (type: keyof typeof ModelPathType[keyof typeof ModelPathType], objects: Record<string, AvailableValue>) => string
    customError: (message: string) => Error
    routerArrayData: <T extends ModelPathType>(type: T, pathname: string) => [AvailableValue[] | [], number, number]
    reassignObject: <T extends ModelPathType>(type: T, pathname: string) => ReassignObjectReturnType

    toNumber(v: string): number

    toNumber(v: string[]): AvailableValue[]

    backToSimple(value: AvailableValue): AvailableValue

    backToSimple(value: AvailableValue[]): AvailableValue[]
  }

  export interface ModelInterface {
    multiCategoryScreening(parameter: MultiCategoryScreening.TransferType): MultiCategoryScreening.ReturnType

    createModelListURL<T extends ModelPathType>(
      type: T,
      key?: FnKeepsakeKeyType<T>[] | FnKeepsakeKeyType<T>,
      value?: number[] | string[] | AvailableValue[],
      useTheCurrentPathToChange?: string | boolean
    ): string

    createModelListURL(
      type: ModelPathType,
      key?: FnKeepsakeKeyType<ModelPathType> | string,
      value?: AvailableValue,
      useTheCurrentPathToChange?: string | boolean
    ): string

    fetchModelParameterValue<T extends ModelPathType, U extends ModelParamsKey<T> | ModelParamsKey<T>[] | []>(
      type: T,
      parameter: U,
      availablePath?: string | boolean
    ): FetchReturnType<T, U, AvailableValue>
  }

  export const SUBCLASS = ['cate_id', 'style', 'attribute1', 'attribute2', 'attribute3'] as const

  export enum ModelPathType {
    MODEL = 'models/model',
    SU = 'models/su',
  }

  export const ALL_MODELS_PARAMS = {
    [ModelPathType.MODEL]: { cate_pid: 0 },
    [ModelPathType.SU]: { cate_pid: 0 },
  }

  abstract class Utils implements UtilsInterface {
    readonly MULTI_CATEGORY_SEPARATOR = '_'

    toNumber(v: string): number
    toNumber(v: string[]): AvailableValue[]
    toNumber(v: string[] | string): number | AvailableValue[] {
      return isNumber(v) ? Number(v) : this.backToSimple(v as string[])
    }

    joinObjectValues: UseModels.UtilsInterface['joinObjectValues'] = (type, objects) => {
      for (const key in objects) {
        if (Object.prototype.hasOwnProperty.call(objects, key))
          objects[key] = objects[key].toString()
      }

      return `/${type}-${Object.values(objects).join('-')}.html`
    }

    customError: UseModels.UtilsInterface['customError'] = (message): Error => {
      throw new Error(message)
    }

    backToSimple(value: AvailableValue): AvailableValue
    backToSimple(value: AvailableValue[]): AvailableValue[]
    backToSimple(value: AvailableValue | AvailableValue[]) {
      const toNum = (v: AvailableValue) => isNumber(v) ? this.toNumber(String(v)) : v

      return isArray(value) ? value.map(v => toNum(v)) : toNum(value)
    }

    routerArrayData: UseModels.UtilsInterface['routerArrayData'] = (type, pathname) => {
      const routerArray = pathname.match(/([\d_]+(-[\d_]+)*)/g)?.join('')?.split('-') ?? []

      return [
        routerArray,
        routerArray.length,
        Object.keys(ALL_MODELS_PARAMS[type]).length,
      ]
    }

    reassignObject: UseModels.UtilsInterface['reassignObject'] = (type, pathname) => {
      const [routerArray] = this.routerArrayData(type, pathname)
      const currentRouterResult: ReassignObjectReturnType = {}

      Object.keys(ALL_MODELS_PARAMS[type]).forEach((key: keyof ModelObjectsKeyType, index) =>
        currentRouterResult[key] = this.backToSimple(routerArray[index]),
      )

      return currentRouterResult
    }
  }

  export class ModelFn extends Utils implements ModelInterface {
    multiCategoryScreening: UseModels.ModelInterface['multiCategoryScreening'] = (parameter) => {
      const [DEFAULT_ID, SELF] = [0 as const, new ModelFn()]

      const { id, subclass, type, maxLength, firstID, pathname, keyword } = parameter
      const currentRouterResult = this.reassignObject(type, pathname)

      const delimiterConnect = (array: AvailableValue[]) => array.join(this.MULTI_CATEGORY_SEPARATOR)

      const checkMulti: number | number[] = isString(this.backToSimple(currentRouterResult[subclass]))
        ? (currentRouterResult[subclass] as string).split(this.MULTI_CATEGORY_SEPARATOR).map(v => +v)
        : this.backToSimple(currentRouterResult[subclass]) as number
      const isMultiArrays = isArray(checkMulti)
      const assignmentKeyword = keyword && String(keyword)?.trim() ? `?keyword=${String(keyword).trim()}` : ''

      const clearZero = (array: number[]) => delimiterConnect(array.filter(v => v !== DEFAULT_ID))
      const clearCategory = () => {
        const optionalCategory: SubclassKeyType[] = ['cate_id']
        const clearCategory: SubclassKeyType[] = ['style', 'attribute1', 'attribute2', 'attribute3']

        if (optionalCategory.includes(subclass))
          clearCategory.forEach(item => currentRouterResult[item] = DEFAULT_ID)

        currentRouterResult.page = 1
      }

      if (isMultiArrays ? (firstID ? checkMulti.slice(1) : checkMulti).find(v => v === id) : checkMulti === id) {
        currentRouterResult[subclass] = isMultiArrays
          ? firstID
            ? delimiterConnect([
              isMultiArrays && checkMulti.filter(v => v !== firstID).length ? DEFAULT_ID : firstID,
              ...checkMulti.slice(1).filter(v => v !== id),
            ])
            : delimiterConnect(checkMulti.filter(v => v !== id))
          : DEFAULT_ID
      }
      else {
        if (id === DEFAULT_ID) {
          currentRouterResult[subclass] = DEFAULT_ID
        }
        else if (isMultiArrays && checkMulti.length >= maxLength) {
          const originalArray = firstID ? [firstID, ...checkMulti] : checkMulti

          firstID ? originalArray.splice(1, originalArray.length - maxLength) : originalArray.shift()
          currentRouterResult[subclass] = delimiterConnect([...originalArray, id])
        }
        else {
          currentRouterResult[subclass] = firstID
            ? clearZero(isMultiArrays ? [firstID, ...checkMulti, id] : [firstID, checkMulti, id])
            : clearZero(isMultiArrays ? [...checkMulti, id] : [checkMulti, id])
        }
      }

      function* generateSubclassArray(): Generator<MultiCategoryScreening.SubclassArraysType, void> {
        const [keys, originValues] = [
          Object.keys(currentRouterResult),
          String(SELF.reassignObject(type, pathname)[subclass]).split(SELF.MULTI_CATEGORY_SEPARATOR),
        ]

        do {
          const key = <SubclassKeyType>keys.shift()

          if (SUBCLASS.includes(key)) {
            const routerResultArray = String(currentRouterResult[key]).split(SELF.MULTI_CATEGORY_SEPARATOR)

            yield <MultiCategoryScreening.SubclassArraysType>{
              key,
              preselectionValues:
                routerResultArray.length > 1 ? SELF.toNumber(routerResultArray) : +currentRouterResult[key],
              alreadySelectValues:
                originValues.length > 1
                  ? firstID ? SELF.toNumber(originValues).slice(1) : SELF.toNumber(originValues)
                  : +originValues.join(''),
            }
          }
        } while (keys.length > 0)
      }

      clearCategory()

      return {
        url: `/${type}-${Object.values(currentRouterResult).join('-')}.html${assignmentKeyword}`,
        subclassArrays: [...generateSubclassArray.bind(this)()],
      } as UseModels.MultiCategoryScreening.ReturnType
    }

    createModelListURL<T extends ModelPathType>(
      type: T,
      key?: FnKeepsakeKeyType<T>[] | FnKeepsakeKeyType<T>,
      value?: number[] | string[] | AvailableValue[],
      useTheCurrentPathToChange?: string | boolean
    ): string
    createModelListURL(
      type: ModelPathType,
      key?: FnKeepsakeKeyType<ModelPathType> | string,
      value?: AvailableValue,
      useTheCurrentPathToChange?: string | boolean
    ): string
    createModelListURL<T extends ModelPathType>(
      type: T,
      key?: FnKeepsakeKeyType<T> | FnKeepsakeKeyType<T>[] | string,
      value?: AvailableValue | number[] | string[] | AvailableValue[],
      useTheCurrentPathToChange: string | boolean = false,
    ): string {
      if (key && !value)
        this.customError('A value must be provided when a key is provided.')

      if (!key)
        return this.joinObjectValues(type, ALL_MODELS_PARAMS[type])

      if (isArray(key) !== isArray(value))
        this.customError('The type of key and value must be the same.')

      if (isString(key) && !Object.keys(ALL_MODELS_PARAMS[type]).find(item => item == key))
        this.customError(`"${key}" is not a valid parameter.`)

      const pathname = isString(useTheCurrentPathToChange) ? useTheCurrentPathToChange : window.location.pathname

      if (useTheCurrentPathToChange) {
        if (!pathname.includes(`${type}-`)) {
          this.customError(`"${pathname}" path does not match, needs to match at: ${type}-.`)
        }
        else {
          const [, inputLength, fixedLength] = this.routerArrayData(type, pathname)

          if (inputLength !== fixedLength)
            this.customError(`Your route parameter length is ${inputLength}, the expected length is ${fixedLength}.`)
        }
      }

      const currentParams = (
        useTheCurrentPathToChange ? this.reassignObject(type, pathname) : ALL_MODELS_PARAMS[type]
      ) as ModelParamsWithIndexSignature<T>

      if (isArray(key) && isArray(value)) {
        key.length !== value.length && this.customError('The lengths of \'key\' and \'value\' arrays do not match.')

        for (const index of key) {
          if (index in currentParams)
            (currentParams[index] as AvailableValue) = value[key.indexOf(index)]
        }
      }
      else {
        (currentParams[key as ModelParamsKey<T>] as AvailableValue) = value as AvailableValue
      }

      return this.joinObjectValues(type, currentParams)
    }

    fetchModelParameterValue<T extends ModelPathType, U extends ModelParamsKey<T> | ModelParamsKey<T>[] | []>(
      type: T,
      parameter: U,
      availablePath: string | boolean = true,
    ): FetchReturnType<T, U, AvailableValue> {
      const pathname = isString(availablePath) ? availablePath : window.location.pathname
      const [routerArray, inputLength, fixedLength] = this.routerArrayData(type, pathname)

      if (!pathname.includes(type) || inputLength !== fixedLength) {
        this.customError(
          `${!pathname.includes(type)
            ? `The incoming path or the automatically obtained path does not contain "${type}"`
            : `Your route parameter length is ${inputLength}, the expected length is ${fixedLength}.`
          }`,
        )
      }

      const mergeObjects = Object.keys(ALL_MODELS_PARAMS[type]).reduce(
        (merged, key, index) => {
          merged[key] = routerArray[index]
          return merged
        },
        {} as { [key: string]: AvailableValue },
      )

      if (isArray(parameter)) {
        let objects = {};

        ((!parameter.length ? Object.keys(ALL_MODELS_PARAMS[type]) : parameter) as string[]).forEach((item) => {
          const eachItem = mergeObjects[item]

          if (eachItem) {
            objects = Object.assign(objects, {
              [item]: this.backToSimple(eachItem),
            })
          }
        })

        return objects as FetchReturnType<T, U, never>
      }

      return this.backToSimple(mergeObjects[parameter as string]) as FetchReturnType<T, U, AvailableValue>
    }
  }
}