12.常用工具函数

/****************************************** Array start ******************************************/

// 初始化数组
// Array(len).fill() === Array.from({length: len}) ????
const ArrayInitWithLen = len => Array(len).fill().map((v, i) => i++)
const ArrayInitWithRange = (start, end) => Array.from({ length: end - start }).map((v, i) => i + start)
const ArrayInitWithVal = (len, val) => Array(len).fill(val)
// 返回最大值元素
const ArrayMax = arr => Math.max(...arr)
// 返回最小值元素
const ArrayMin = arr => Math.min(...arr)
// 返回一个数字数组的总和
const ArraySum = arr => arr.reduce((acc, val) => acc + val, 0)
// 返回数字数组的平均值
const ArrayAverage = arr => ArraySum(arr)/arr.length
// 返回数字数组的中间值
const ArrayMiddle = arr => {
  let mid = Math.floor(arr.length / 2),
    nums = arr.sort((a, b) => a - b)
  return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;
}

/**
 * [数组排序]
 * @param  {[type]} arr  [数组]
 * @param  {[type]} key) [key]
 * @return {[type]}      [description]
 */
const ArraySortBy = (arr, key) => arr.sort((a, b) => {
  if(key === undefined){
    return a - b
  }else if(typeof key === 'function'){
    return arr.sort(key)
  }else if(isNaN(a[key])){
    return a[key].localeCompare(b[key])
  }else{
    return a[key] - b[key]
  }
})
// 扁平化数组
const ArrayFlat = (arr, depth = Infinity) => arr.flat(depth)
// 数组去重
const ArrayDuplicate = arr => [...new Set(arr)]
// 将数组按照长度分段
const ArrayChunk = (arr, len) => Array.from({ length: Math.ceil(arr.length / len) }, (v, i) => arr.slice(i * len, i * len + len))
// 筛选出 falsey 值 ( false、 null、 0、 ''、 undefined 和 NaN )
const ArrayCompact = arr => arr.filter(Boolean)
// 返回唯一值
const ArrayUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i));
// 随机数组值的顺序
const ArrayShuffle = arr => arr.sort(() => Math.random() - 0.5);
// 计算元素出现的次数
const ArrayCountOccurrences = (arr, val) => arr.reduce((a, v) => v === val ? a + 1 : a, 0)
// 返回数组中每间隔第 n 个元素
const ArrayEveryNth = (arr, nth) => arr.filter((e, i) => i % nth === 0)
// 返回两个数组中都存在的元素
const ArraySimilarity = (arr1, arr2) => arr1.filter(v => arr2.includes(v))
// 返回第一个数组与第二个数组不同的元素
const ArrayDifference = (arr1, arr2) => { let s = new Set(arr2); return arr1.filter(x => !s.has(x)); }
// 返回两个数组之间的差集(差异的部分)
const ArraySymmetricDifference = (arr1, arr2) => {
  let sA = new Set(arr1),
    sB = new Set(arr2);
  return [...arr1.filter(x => !sB.has(x)), ...arr2.filter(x => !sA.has(x))]
}

/******************************************* Array end *******************************************/


/******************************************* Date start ******************************************/

// 返回两个日期之间的差异 (以天为值)
const DateGetDaysBetween = (start, end) => (start - end) / (1000 * 3600 * 24)

/******************************************* Date end ********************************************/


/****************************************** Number start *****************************************/

// 返回指定范围内的随机数, floor 是否生成整数
const NumberRandomInRange = (min, max, floor) => {
  let random = Math.random() * (max - min + floor)
  return (floor ? Math.floor(random) : random) + min
}
// 将数字四舍五入到指定的位数
const NumberRound = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`).toFixed(decimals)

/******************************************* Number end ******************************************/


/****************************************** String start *****************************************/

// 将字符串的第一个字母大写
const StringCapitalize = ([first, ...rest], lowerRest = false) => first.toUpperCase() + (lowerRest ? rest.join('').toLowerCase() : rest.join(''))
// 将字符串中每个单词的首字母大写
const StringCapitalizeEvery = str => str.replace(/\b[a-z]/g, char => char.toUpperCase())
// 从匹配转换字符串(将驼峰写法转换成自定义分隔符的写法)
const StringFromCamelCase = (str, separator = '_') => str.replace(/([a-z\d])([A-Z])/g, '$1' + separator + '$2').replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + separator + '$2').toLowerCase();
// 将字符串转换为匹配
const StringToCamelCase = str => str.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2, offset) => p2 ? p2.toUpperCase() : p1.toLowerCase())
// 反转字符串
const StringReverse = str => [...str].reverse().join('')
// 按字母顺序对字符串中的字符进行排序
const StringSort = str => str.split('').sort((a, b) => a.localeCompare(b)).join('')
// 将字符串截断为指定长度, 并拼接自定义字符串
const StringTruncate = (str, num, separator = '...') => str.length > num ? str.slice(0, num) + separator : str

/******************************************* String end ******************************************/



/********************************************* is start ******************************************/

const isArray = val => Array.isArray(val)
const isString = val => typeof val === 'string'
const isNumber = val => typeof val === 'number'
const isBoolean = val => typeof val === 'boolean'
const isFunction = val => typeof val === 'function'
const isSymbol = val => typeof val === 'symbol'
// 基本类型
const isStatic = type => type === null || ['string','number', 'boolean', 'undefined', 'symbol'].includes(typeof type)
// 注意: function 不是 原始类型,这里加进去是因为可以用 typeof 返回
const isUndefined = type => typeof type === 'undefined'
const isNull = type => type === null

/********************************************** is end *******************************************/


/******************************************* getType start ***************************************/

const getRef = function (obj) {
  let _type = Object.prototype.toString.call(obj).slice(8, -1)
  let map = {
    'Array': 'array',
    'Object': 'object',
    'Function': 'function',
    'Date': 'date',
    'RegExp': 'regExp'
  }
  return map[_type]
}

const getType = function (obj) {
  return obj === null ? 'null' : isStatic(obj) ? typeof obj : getRef(obj)
}

/********************************************* getType end ***************************************/


/******************************************* DOM start *******************************************/

// 如果页面的底部可见, 则返回true , 否则为false
const DomIsBottomVisible = () => document.documentElement.clientHeight + window.scrollY >= document.documentElement.scrollHeight || document.documentElement.clientHeight
// 如果指定的元素在视区中可见, 则返回true , 否则为false。 第二个参数是否完全可见
const DomIsElementInViewport = (el, partiallyVisible = false) => {
  let { top, left, bottom, right } = el.getBoundingClientRect();
  return partiallyVisible ?
    ((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) && ((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth)) :
    top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth
};
// 返回当前页的滚动位置
const DomGetScrollPosition = (el = window) => {
  return {
    x: (el.pageXOffset !== undefined) ? el.pageXOffset : el.scrollLeft,
    y: (el.pageYOffset !== undefined) ? el.pageYOffset : el.scrollTop
  }
}
// 元素
const DomGetEle = el => document.querySelector(el)
const DomGetEles = el => document.querySelectorAll(el)
const DomEleToArray = el => Array.from(DomGetEles(el))
// classList
const DomGetEleClass = el => DomGetEle(el).classList
const DomEleHasClass = (el, cls) => DomGetEleClass(el).contains(cls)
const DomToggleClass = (el, cls) => DomGetEleClass(el).toggle(cls)
// 属性
const DomGetEleAttr = (el, key) => DomGetEle(el).getAttribute(key)
const DomSetEleAttr = (el, key) => DomGetEle(el).setAttribute(key)
// 位置尺寸
const DomGetEleClientRect = (el, key) => {
  let rect = DomGetEle(el).getBoundingClientRect();
  return !!key ? rect[k] : rect
}
// 这里这里还不清楚 offsetHeight 与 clientHeight 的区别
const DomGetEleOffset = (el, key) => {
  if(!!key) throw new Error('missing required options')
  return DomGetEle(el)[`offset${StringCapitalize(key)}`]
}
const DomGetEleClient = (el, key) => {
  if(!!key) throw new Error('missing required options')
  return DomGetEle(el)[`Client${StringCapitalize(key)}`]
}
// 平滑滚动到页面顶部
const DomScrollToTop = () => {
  let c = document.documentElement.scrollTop || document.body.scrollTop;
  if (c > 0) {
    window.requestAnimationFrame(DomScrollToTop);
    window.scrollTo(0, c - c / 8);
  }
}

/******************************************** DOM end ********************************************/


/******************************************* BOM start *******************************************/

// 返回当前 URL
const BomGetCurrentURL = () => window.location.href
// 返回一个包含当前 URL 参数的对象
const BomGetURLParams = url => url.match(/([^?=&]+)(=([^&]*))/g).reduce((a, v) => (a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1), a), {})

/******************************************** BOM end ********************************************/

exports._is = {
  string: isString,
  number: isNumber,
  boolean: isBoolean,
  _undefined: isUndefined,
  _null: isNull,
  symbol: isSymbol,
  function: isFunction,
  array: isArray,
  static: isStatic,
}

exports._type = {
  getRef: getRef,
  getType: getType,
}

exports._string = {
  capitalizeFirst: StringCapitalize,
  capitalizeEvery: StringCapitalizeEvery,
  fromCamelCase: StringFromCamelCase,
  toCamelCase: StringToCamelCase,
  reverse: StringReverse,
  sort: StringSort,
  truncate: StringTruncate
}

exports._date = {
  getDaysBetween: DateGetDaysBetween
}


exports._number = {
  randomInRange: NumberRandomInRange,
  round: NumberRound
}


exports._array = {
  initWithLen: ArrayInitWithLen,
  initWithRange: ArrayInitWithRange,
  initWithVal: ArrayInitWithVal,
  max: ArrayMax,
  min: ArrayMin,
  sum: ArraySum,
  average: ArrayAverage,
  middle: ArrayMiddle,
  sortBy: ArraySortBy,
  flat: ArrayFlat,
  duplicate: ArrayDuplicate,
  chunk: ArrayChunk,
  compact: ArrayCompact,
  unique: ArrayUnique,
  shuffle: ArrayShuffle,
  countOccurrences: ArrayCountOccurrences,
  everyNth: ArrayEveryNth,
  similarity: ArraySimilarity,
  difference: ArrayDifference,
  symmetricDifference: ArraySymmetricDifference,
}

exports._object = {
}

exports._clone = {
}

exports._dom = {
  isBottomVisible: DomIsBottomVisible,
  isElementInViewport: DomIsElementInViewport,
  getScrollPosition: DomGetScrollPosition,
  getEle: DomGetEle,
  getEles: DomGetEles,
  eleToArray: DomEleToArray,
  getClass: DomGetEleClass,
  hasClass: DomEleHasClass,
  toggleClass: DomToggleClass,
  getAttr: DomGetEleAttr,
  setAttr: DomSetEleAttr,
  getClientRect: DomGetEleClientRect,
  getOffset: DomGetEleOffset,
  getClient: DomGetEleClient,
  scrollToTop: DomScrollToTop,
}

exports._bom = {
  getCurrentURL: BomGetCurrentURL,
  getURLParams: BomGetURLParams,
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345

推荐阅读更多精彩内容