/////////////////////////////////////////////////////////////////////
//Array对象 Object.defineProperty 增加额外的函数方法
// 在app.js 中增加require即可
///////////////////////////////////////////////////////////////////// 
const proObj = require('./prototypeObject')

// Array.prototype.at函数
if (!Array.prototype.at) {
  const atFunc = function (idx) {
    idx = Math.trunc(idx) || 0;
    if (idx < 0) idx += this.length;
    if (idx < 0 || idx >= this.length) return undefined;
    return this[idx];
  }
  if (Object.defineProperty) {
    Object.defineProperty(Array.prototype, "at", {
      'value': atFunc,
      'configurable': false,
      'writable': false,
      'configurable': true,
    });
  } else {
    Array.prototype.at = atFunc;
  }
}

/**
 * 将一个数组元素清空
 * @return {Array}
 */
Array.prototype.clear = function () {
  this.length = 0;
  return this;
}
/**
 * 计算一个数组的长度
 * @return {*}
 */
Array.prototype.size = function () {
  return this.length;
}
/**
 * 返回数组里面的第一个元素
 * @return {*}
 */
Array.prototype.first = function () {
  return this[0];
}
/**
 * 返回数组的最后一个元素
 * @return {*}
 */
Array.prototype.last = function () {
  return this[this.length - 1]
}

/**
 * 对数组的所有元素进行求和
 * @return {*}
 */
Array.prototype.sum = function (name) {
  if (!name) {
    return this.reduce((acc, cur) => (parseFloat(cur) + acc), 0);
  } else {
    return this.filter(it => it[name]).map(it => it[name]).reduce(
      (acc, cur) => (parseFloat(cur) + acc), 0);
  }
}
/**
 * 找出数组中的最大值
 * @return {*}
 */
Array.prototype.max = function (name) {
  if (!name) {
    return this.reduce((acc, cur) => acc > cur ? acc : cur);
  } else {
    return this.filter(it => it[name]).map(it => it[name]).reduce(
      (acc, cur) => acc > cur ? acc : cur);
  }
}
/**
 * 找出一个数组中的最小值
 * @return {*}
 */
Array.prototype.min = function (name) {
  if (!name) {
    return this.reduce((acc, cur) => acc < cur ? acc : cur);
  } else {
    return this.filter(it => it[name]).map(it => it[name]).reduce(
      (acc, cur) => acc < cur ? acc : cur);
  }
}

/**
 * 求出一个数组中所有元素的平均值
 * @return {*}
 */
Array.prototype.avg = function () {
  // 1. 先对数组中的元素个数组进行判断一下，防止计算出现无穷的情况
  if (this.length === 0) {
    return;
  }
  var sum = this.sum();
  return sum / this.length;
  /*return cacl(this, function (item, avg) {
      // 1. 先求和(进入到这个函数里面， this指向的是window对象，此时window对象是没有sum方法的，故执行错误)
      //var sum = this.sum();
      // 2.求出平均值
      if (typeof avg === 'undefined'){
          return item;
      } else{
          avg = sum / (this.length);
      }
      return avg;
  })*/
}


/**
 * @desc   : 数组去重
 * @author : 周兴
 * @date   : 2022/12/14 16:14
 */
Array.prototype.unique = function () {
  if (!this || this.length == 0) return this;
  console.log('ttt',typeof this[0],typeof this[0] === 'object');
  if (typeof this[0] === 'object') {
    let arr = []
    return this.filter(item => !arr.has(item) && arr.push(item))
  } else {
    return Array.from(new Set(this));
  }
}

/**
 * @desc   : 判断数组中是否包含这个对象
 * @author : 周兴
 * @date   : 2022/11/16 9:11
 */
Array.prototype.has = function (obj) {
  if (this && this.length > 0) {
    for (let i of this) {
      if (proObj.objEqual(i, obj)) {
        return true;
      }
    }
    return false;
  }
}


/**
 * @desc   : 取得原数组跟目标数组的交集
 * @author : 周兴
 * @date   : 2022/11/15 17:21
 */
Array.prototype.intersection = function (arr) {
  if (!this || !arr || arr.length == 0) return this;
  // 如果第一个是对象，那么就按照对象数组来进行
  if (typeof arr[0] == 'object') {
    return this.filter(it => arr.has(it))
  }
  return this.filter(it => arr.includes(it))
}

/**
 * @desc   : 取得原数组跟目标数组的并集
 * @author : 周兴
 * @date   : 2022/11/15 17:26
 */
Array.prototype.union = function (...arr) {
  if (!this || !arr || arr.length == 0) return this;
  return this.concat(...arr)
}

/**
 * @desc   : 取得原数组跟目标数组的差集
 * @author : 周兴
 * @date   : 2022/11/15 17:26
 * @param  : arr：目标数组；cols,需要判断的列
 */
Array.prototype.minus = function (arr, cols = []) {
  if (!this || !arr || arr.length == 0) return this;
  // 如果第一个是对象，那么就按照对象数组来进行
  if (typeof arr[0] == 'object') {
    if (!cols || cols.length === 0) {
      return this.filter(it => !arr.has(it))
    } else {
      let arrt = arr.map(it => {
        let item = {}
        cols.forEach(col => {
          item[col] = it[col]
        })
        return item;
      })
      let thisTable = this.map(it => {
        let item = {}
        cols.forEach(col => {
          item[col] = it[col]
        })
        return item;
      })
      return thisTable.filter(it => !arrt.has(it))
    }
  }
  return this.filter(it => !arr.includes(it))
}

/**
 * @desc   : 数组的复制
 * @author : 周兴
 * @date   : 2022/12/8 17:45
 */
Array.prototype.copy = function () {
  if (!this) return this;
  return JSON.parse(JSON.stringify(this));
}

/**
 * 找出两个数组中的不同元素
 * @param target
 * @return {Array|*[]}
 */
Array.prototype.diff = function (target) {
  // 1. 获取原始数组和目标数组，去除重复项
  var orignArr = this.unique(),
    targetArr = target.unique();
  // 2. 开始使用filter函数过滤条件
  return orignArr.filter(function (element, index, array) {
    for (var i = 0, len = targetArr.length; i < len; i++) {
      // 只要元素相等的话，就全部过滤掉
      if (element === targetArr[i]) {
        return false;
      }
    }
    return true;
  });
}

/**
 * 对数组的每一项遍历的时候设置一个回调函数（没有返回结果）
 * @param fn
 * @param ctx
 */
Array.prototype.forEach = function (fn, ctx) {
  var i = 0,
    len = this.length;
  for (; i < len; i++) {
    // element, index, array
    // call 的第一个参数也就是this的指向， 其他参数表示需要传递给回调函数的的参数
    fn.call(ctx || null, this[i], i, this);
  }
}
/**
 * 返回index，如果没有返回-1
 * @param {*} val 
 */
Array.prototype.find = function(val) {
  for (var i = 0; i < this.length; i++) {
      if (val == this[i]) {
          return i;
      }
  }
  return -1;
} 

