# 函数

# 1. 函数节流

/* 
  函数节流
- 语法: throttle(callback, delay)
- 功能: 创建一个节流函数,在 delay 毫秒内最多执行 `callback` 一次
- return function
*/
function throttle(callback, delay) {
  let start = 0
  return function (event) {
    const current = Date.now()
    if ( current - start > delay) {
      callback.call(this, event) 
      start = current
    }
  }
}

# 2. 函数防抖

/* 
  函数防抖
- 语法: debounce(callback, delay)
- 功能: 创建一个防抖动函数,该函数会从上一次被调用后,延迟 `delay` 毫秒后调用 `callback`
*/
function debounce (callback, delay) {
  let timeoutId = -1 
  return function (event) {
    // 自上次点击后,函数还未执行,再次点击时候清除未执行的定时器任务
    if (timeoutId!==-1) {
      clearTimeout(timeoutId)
    }
    timeoutId = setTimeout(() => {
      callback.call(this, event)
      timeoutId = -1
    }, delay)
  }
}

# 3. 活动周期数据加工

TODO:只支持手动传入时间,后续可能支持自动识别时间调整阶段

/**
 * 
 * @param {
 * data<Array> 数据 
 * startYear<number> 开始年份  2022
 * startMonth<number> 从几月份开始 1
 * startDay<number> 从哪天开始  29
 * startTime<string> 开始时分秒 hh:mm:ss
 * endTime<string> 结束时分秒 hh:mm:ss
 * } options 
 * @returns 数组,每个数据会在原基础上新增这些字段返回
 * result{
    beginTime: String, -- 开始时间  YYYY-MM-DD hh:mm:ss
    current: boolean, -- 当前是否处于活动时间之内
    yeat: number --YYYY
    month: number, -- MM
    day: number, -- DD
    endTime: string, -- 结束时间  YYYY-MM-DD hh:mm:ss
    expired: boolean, -- 是否过期
    unlock: boolean, -- 激活状态
  }
 */
function handleStages(options){
      let { startYear, startMonth, startDay, startTime, endTime } = options;
      // 深克隆一层,避免改变原数据, wran: 使用此方法,默认对JSON方法克隆有所了解。
      const data = JSON.parse(JSON.stringify(options.data))
      const oDate = new Date();
      const curTime = oDate.getTime();
      const year = startYear || oDate.getFullYear();
      const days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
      if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
        days.splice(1, 1, 29);
      }
      const result = data.map((item) => {
        if (startDay > days[startMonth - 1]) {
          startDay = 1;
          startMonth++;
        }
        if (startMonth > 12) {
          startMonth = 1;
          startYear++;
        }
        if(startDay<10){
          startDay = `0${startDay}`
        }
        item.year = startYear;
        item.month = startMonth;
        item.day = parseInt(startDay);
        item.beginTime = `${startYear}/${startMonth}/${startDay} ${startTime}`;
        item.endTime = `${startYear}/${startMonth}/${startDay} ${endTime}`;
        const bTime = new Date(item.beginTime).getTime();
        const eTime = new Date(item.endTime).getTime();
        if (curTime < bTime) {
          item.current = false;
          item.unlock = false;
          item.expired = false;
        }
        if (curTime > bTime) {
          item.current = false;
          item.unlock = true;
        }
        if (curTime > bTime && curTime < eTime) {
          item.current = true;
          item.expired = false;
        }
        if (curTime > eTime) {
          item.expired = true;
        }
        startDay++;

        return item;
      });
      return result;
}

# 4. 加减乘除


/**
 * 加法运算
 * @param {Number} a
 * @param {Number} b
 * @example addNum(0.3 , 0.6) // => 0.9
 */
function addNum(a, b) {
  let c; let d; let e;
  try {
    c = a.toString().split('.')[1].length;
  } catch (f) {
    c = 0;
  }
  try {
    d = b.toString().split('.')[1].length;
  } catch (f) {
    d = 0;
  }
  return (e = Math.pow(10, Math.max(c, d))), (mulNum(a, e) + mulNum(b, e)) / e;
};

/**
 * 减法运算
 * @param {Number} a
 * @param {Number} b
 * @example subNum(0.3 , 0.2) // => 0.1
 */
function subNum(a, b){
  let c; let d; let e;
  try {
    c = a.toString().split('.')[1].length;
  } catch (f) {
    c = 0;
  }
  try {
    d = b.toString().split('.')[1].length;
  } catch (f) {
    d = 0;
  }
  return (e = Math.pow(10, Math.max(c, d))), (mulNum(a, e) - mulNum(b, e)) / e;
};

/**
 * 乘法运算
 * @param {Number} a
 * @param {Number} b
 * @example mulNum(0.3 , 1.5) // => 0.45
 */
function mulNum (a, b) {
  let c = 0;
  const d = a.toString();
  const e = b.toString();
  try {
    c += d.split('.')[1].length;
  } catch (f) {}
  try {
    c += e.split('.')[1].length;
  } catch (f) {}
  return (Number(d.replace('.', '')) * Number(e.replace('.', ''))) / Math.pow(10, c);
};

/**
 * 除法运算
 * @param {Number} a
 * @param {Number} b
 * @example divNum(0.3 , 0.1) // => 3
 */
function divNum(a, b){
  let c;
  let d;
  let e = 0;
  let f = 0;
  try {
    e = a.toString().split('.')[1].length;
  } catch (g) {}
  try {
    f = b.toString().split('.')[1].length;
  } catch (g) {}
  return (
    (c = Number(a.toString().replace('.', ''))),
    (d = Number(b.toString().replace('.', ''))),
    mulNum(c / d, Math.pow(10, f - e))
  );
}


# 5. 类型判断

/**
 * 判断传入数据是否为 null
 * @param value
 * @returns {boolean}
 */
 const isNull = value => Object.prototype.toString.call(value) === '[object Null]';

/**
 * 判断传入数据是否为 undefined
 * @param value
 * @returns {boolean}
 */
 const isUndefined = value => Object.prototype.toString.call(value) === '[object Undefined]';

/**
 * 判断传入数据是否为 Number
 * @param value
 * @returns {boolean}
 */
 const isNumber = value => Object.prototype.toString.call(value) === '[object Number]';

/**
 * 判断传入数据是否为 Boolean
 * @param value
 * @returns {boolean}
 */
 const isBoolean = value => Object.prototype.toString.call(value) === '[object Boolean]';

/**
 * 判断传入数据是否为 String
 * @param value
 * @returns {boolean}
 */
 const isString = value => Object.prototype.toString.call(value) === '[object String]';

/**
 * 判断传入数据是否为 Object
 * @param value
 * @returns {boolean}
 */
 const isObject = value => Object.prototype.toString.call(value) === '[object Object]';

/**
 * 判断传入数据是否为 Symbol
 * @param value
 * @returns {boolean}
 */
 const isSymbol = value => Object.prototype.toString.call(value) === '[object Symbol]';

/**
 * 判断传入数据是否为 Array
 * @param value
 * @returns {boolean}
 */
 const isArray = value => Object.prototype.toString.call(value) === '[object Array]';

/**
 * 判断传入数据是否为 Function
 * @param value
 * @returns {boolean}
 */
 const isFunction = value => Object.prototype.toString.call(value) === '[object Function]';

/**
 * 判断传入数据是否为 Date
 * @param value
 * @returns {boolean}
 */
 const isDate = value => Object.prototype.toString.call(value) === '[object Date]';

/**
 * 判断传入数据是否为 Math
 * @param value
 * @returns {boolean}
 */
 const isMath = value => Object.prototype.toString.call(value) === '[object Math]';

/**
 * 判断传入数据是否为 Set
 * @param value
 * @returns {boolean}
 */
 const isSet = value => Object.prototype.toString.call(value) === '[object Set]';

/**
 * 判断传入数据是否为 WeakSet
 * @param value
 * @returns {boolean}
 */
 const isWeakSet = value => Object.prototype.toString.call(value) === '[object WeakSet]';
/**
 * 判断传入数据是否为 Map
 * @param value
 * @returns {boolean}
 */
 const isMap = value => Object.prototype.toString.call(value) === '[object Map]';

/**
 * 判断传入数据是否为 WeakMap
 * @param value
 * @returns {boolean}
 */
 const isWeakMap = value => Object.prototype.toString.call(value) === '[object WeakMap]';


/**
 * 获取传入数据的类型
 * @example getType(1) // => "number"
 * @param {any} value
 * @returns {String} 返回传入数据所属类型的小写
 */
const getType = value => Object.prototype.toString.call(value)
  .match(/\s([a-z]+)/i)[1]
  .toLocaleLowerCase();

# 6. 设备环境判断

const u = navigator.userAgent;

const isIOS = !!u.match(/\(i[^]+( U)? CPU.+Mac OS X/);

const isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;

const isQQ = / QQ/i.test(u);

const isWechat = /MicroMessenger/i.test(u);

const isChrome = u.indexOf('Chrome') > -1;
更新时间: 2022-02-10