interface Array {

  /**
   * 清空数组
   */
  clear(): void;

  /**
   * 清空数组并添加
   * @param items
   */
  newPush(...items: T[]): void;

  /**
   * 数组根据对象删除指定元素
   * @param val
   */
  remove(val: T | T[]): void;

  /**
   * 数组根据下标删除指定元素
   * @param index
   * @param {number} index
   */
  removeByIndex(index: number): void;

  /**
   * 数组指定位置添加元素
   * @param index
   * @param item
   * @param {number} index
   * @param {*} item
   */
  insert(index: number, ...item: T): void;

  /**
   * 数组指定位置替换元素
   * @param index
   * @param item
   * @param {number} index
   * @param {*} item
   */
  replace(index: number, ...item: T): void;

  /**
   * 数组排序（根据某一个字段排序或者直接排序）
   * @param { key, desc } options
   */
  shellSort(options?: {key: string, desc: boolean}): void;


  /**
   * 数组去重 (key为元素中的某一个属性，默认对比整个对象)
   * @param key
   * @returns {*|*[]}
   */
  deDuplication(key?: string): T[];

  /**
   * 判断元素中是否包含此元素 (key为元素中的某一个属性，默认对比整个对象)
   * @param val
   * @param key1
   * @param key2
   * @returns {boolean}
   * @param {any} val
   * @param {string} key1
   * @param {string | null} key2
   */
  contain(val: any, key1?: string, key2?: string): boolean;
}

/**
 * 清空数组
 */
Array.prototype.clear = function() {
  this.length = 0
}

/**
 * 清空数组并添加
 * @param items
 */
Array.prototype.newPush = function(...items: T[]) {
  this.clear()
  // 判断是否传入了多个参数
  if (items && Array.isArray(items)) {
    // 循环多个参数
    for (let i = 0; i < items.length; i++) {
      // 判断每个参数是否为数组
      if (items[i] && Array.isArray(items[i])) {
        // 循环是数组的元素并添加
        for (let j = 0; j < items[i].length; j++) {
          this.push(items[i][j])
        }
      } else {
        this.push(items[i])
      }
    }
  } else {
    this.push(items)
  }
}

/**
 * 数组根据对象删除指定元素
 * @param val
 */
Array.prototype.remove = function (val: T | T[]) {
  const index = this.indexOf(val)
  if (index > -1) {
    this.removeByIndex(index)
  }
}

/**
 * 数组根据下标删除指定元素
 * @param index
 * @param {number} index
 */
Array.prototype.removeByIndex = function (index: number) {
  this.splice(index, 1)
}

/**
 * 数组指定位置添加元素
 * @param index
 * @param item
 * @param {number} index
 * @param {*} item
 */
Array.prototype.insert = function (index: number, item: T) {
  const len = this.length
  if (len < index) {
    for (let i = 0; i < (index - len); i++) {
      this.push(null)
    }
  } else if (index < 0) {
    for (let i = 0; i > index + len; i--) {
      this.splice(i, 0, null)
    }
  }
  this.splice(index, 0, item)
}

/**
 * 数组指定位置替换元素
 * @param index
 * @param item
 */
Array.prototype.replace = function (index: number, item: T) {
  if (index < 0) {
    return
  }
  const len = this.length
  if (len < index) {
    this.insert(index, item)
  } else {
    this.splice(index, 1, item)
  }
}

/**
 * 数组排序（根据某一个字段排序或者直接排序）
 * @param { key, desc } options
 */
Array.prototype.shellSort = function (options?: {key: string, desc: boolean} | null = {}) {
  const {key, desc} = options
  const N = this.length
  let h = 1
  while (h < N / 3) {
    h = 3 * h + 1
  }
  while (h >= 1) {
    for (let i = h; i < N; i++) {
      if (key) {
        for (let j = i; j >= h && (desc ? this[j][key] > this[j - h][key] : this[j][key] < this[j - h][key]); j -= h) {
          const temp = this[j]
          this[j] = this[j - h]
          this[j - h] = temp
        }
      } else {
        for (let j = i; j >= h && (desc ? this[j] > this[j - h] : this[j] < this[j - h]); j -= h) {
          const temp = this[j]
          this[j] = this[j - h]
          this[j - h] = temp
        }
      }
    }
    h = (h - 1) / 3
  }
}

/**
 * 数组去重 (key为元素中的某一个属性，默认对比整个对象)
 * @param key
 * @returns {*|*[]}
 */
Array.prototype.deDuplication = function (key?: string) {
  return this.reduce((pre: Array, cur) => {
    return pre.contain(cur, key) ? pre : pre.concat(cur)
  }, [])
}

/**
 * 判断元素中是否包含此元素 (key为元素中的某一个属性，默认对比整个对象)
 * @param val
 * @param key1
 * @param key2
 * @returns {boolean}
 * @param {any} val
 * @param {string} key1
 * @param {string} key2
 */
Array.prototype.contain = function (val: any, key1?: string, key2?: string): boolean {
  if (key1) {
    if (key2) {
      for (let i = 0; i < this.length; i++) {
        if (typeof val === 'object') {
          if (this[i][key1][key2] === val[key1][key2]) {
            return true
          }
        } else {
          if (this[i][key1][key2] === val) {
            return true
          }
        }
      }
    } else {
      for (let i = 0; i < this.length; i++) {
        if (typeof val === 'object') {
          if (this[i][key1] === val[key1]) {
            return true
          }
        } else {
          // console.log(this[i][key1], '===', val)
          if (this[i][key1] === val) {
            return true
          }
        }
      }
    }
  } else {
    return this.includes(val)
  }
  return false
}














