Javascript Utils

July 07, 2019

javascript 语法基础 ECMAScript 的 Utils

Table of Contents

Number Conversion

// 十进制 转 其他进制
;(10).toString(2) // 10 转 2
;(10).toString(8) // 10 转 8

// 其他进制 转 十进制
parseInt(1010, 2) // 10

throttle

函数节流

function throttle(fn, delay = 0) {
  let last
  let timer
  return function () {
    const now = Date.now()
    if (last && now < last + delay) {
      clearTimeout(timer)

      timer = setTimeout(() => {
        fn.apply(this, arguments)
        last = now
      }, delay)
    } else {
      fn.apply(this, arguments)
      last = now
    }
  }
}

debounce

函数防抖

function debounce(fn, delay = 0) {
  let timer = null
  return function () {
    clearTimeout(timer)
    timer = setTimeout(() => {
      fn.apply(this, arguments)
    }, delay)
  }
}

shuffle

Fisher–Yates 乱序算法

function shuffle(arr) {
  let length = arr.length
  while (length > 1) {
    let index = Math.floor(Math.random() * length--)
    ;[arr[length], arr[index]] = [arr[index], arr[length]]
  }
  return arr
}

randomInt

export function randomInt(min, max) {
  if (min > max) {
    ;[min, max] = [max, min]
  }
  return Math.floor(min + Math.random() * (max - min + 1))
}

async/await-try/catch

简化 promise 函数的异常捕获,类 node API

export default function errorCaptured(promiseFunc) {
  return promiseFunc.then((...args) => [null, ...args]).catch((err) => [err])
}

sleep

export const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))

isStatic

检测数据是不是除了 symbol 外的原始数据

function isStatic(value) {
  const type = typeof value
  return (
    type === 'string' ||
    type === 'number' ||
    type === 'boolean' ||
    type === 'undefined' ||
    value === null
  )
}

isPrimitive

检测数据是不是原始数据

function isPrimitive(value) {
  return isStatic(value) || typeof value === 'symbol'
}

isObject

判断数据是不是引用类型的数据 (例如: Array, Function, Object, Regexp, new Number(0),以及 new String(”))

function isObject(value) {
  const type = typeof value
  return value !== null && (type === 'object' || type === 'function')
}

isObjectLike

检查 value 是否是 类对象。 如果一个值是类对象,那么它不应该是 null,而且 typeof 后的结果是 “object”

function isObjectLike(value) {
  return value !== null && typeof value === 'object'
}

toString

获取数据类型,返回结果为 Number、String、Object、Array 等

function _toString(value) {
  return Object.prototype.toString.call(value).slice(8, -1)
}
// _toString([]) ==> Array

isPlainObject

判断数据是不是 Object 类型的数据

function isPlainObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]'
}

isArray

判断数据是不是数组类型的数据

function isArray(value) {
  return Object.prototype.toString.call(value) === '[object Array]'
}

ES6

Array.isArray

isRegExp

判断数据是不是正则对象

function isRegExp(value) {
  return Object.prototype.toString.call(value) === '[object RegExp]'
}

isDate

判断数据是不是时间对象

function isDate(value) {
  return Object.prototype.toString.call(value) === '[object Date]'
}

isNative

判断 value 是不是浏览器内置函数
内置函数 toString 后的主体代码块为 [native code] ,而非内置函数则为相关代码,所以非内置函数可以进行拷贝(toString 后掐头去尾再由 Function 转)

function isNative(value) {
  return typeof value === 'function' && /native code/.test(value.toString())
}

isFunction

检查 value 是不是函数

function isFunction(value) {
  return Object.prototype.toString.call(value) === '[object Function]'
}

isLength

检查 value 是否为有效的类数组长度

function isLength(value) {
  return (
    typeof value === 'number' &&
    value > -1 &&
    value % 1 === 0 &&
    value <== Number.MAX_SAFE_INTEGER
  )
}

isValidArrayIndex

判断变量是否含有效的数组索引

function isValidArrayIndex(val: any): boolean {
  const n = parseFloat(String(val))
  // n >= 0 && Math.floor(n) === n 保证了索引是一个大于等于 0 的整数
  return n >= 0 && Math.floor(n) === n && isFinite(val)
}

isArrayLike

检查 value 是否是类数组
如果一个值被认为是类数组,那么它不是一个函数,并且 value.length 是个整数,大于等于 0,小于或等于 Number.MAX_SAFE_INTEGER。这里字符串也将被当作类数组。

function isArrayLike(value) {
  return value !== null && isLength(value.length) && !isFunction(value)
}

hasOwn

检查是否自身属性,而不是原型链上的

function hasOwnProperty(value, key) {
  return Object.prototype.hasOwnProperty.call(value, key)
}

isEmpty

检查 value 是否为空
如果是 null,直接返回 true;如果是类数组,判断数据长度;如果是 Object 对象,判断是否具有属性;如果是其他数据,直接返回 true

function isEmpty(value) {
  if (value === null) {
    return true
  }
  if (isArrayLike(value)) {
    return !value.length
  } else if (isPlainObject(value)) {
    for (let key in value) {
      if (hasOwnProperty(value, key)) {
        return false
      }
    }
  }
  return true
}

inBrowser

检测当前宿主环境是否是浏览器

// 通过判断 `window` 对象是否存在即可
const inBrowser = typeof window !== 'undefined'

hasProto

检查当前环境是否可以使用对象的 __proto__ 属性

// 一个对象的 __proto__ 属性指向了其构造函数的原型
// 从一个空的对象字面量开始沿着原型链逐级检查。
const hasProto = '__proto__' in {}

userAgent

获取当浏览器的 user agent

// toLowerCase目的是 为了后续的各种环境检测
const UA = inBrowser && window.navigator.userAgent.toLowerCase()

browserType

使用正则去匹配 UA 中是否包含’msie’或者’trident’这两个字符串即可判断是否为 IE 浏览器

const isIE = UA && /msie|trident/.test(UA)
const isIE9 = UA && UA.indexOf('msie 9.0') > 0
const isEdge = UA && UA.indexOf('edge/') > 0
const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge

toString

将给定变量的值转换为 string 类型并返回

export function toString(val: any): string {
  return val == null
    ? ''
    : typeof val === 'object'
    ? JSON.stringify(val, null, 2)
    : String(val)
}

cached

记忆函数:缓存函数的运算结果

function cached(fn) {
  const cache = Object.create(null)
  return function (str) {
    return cache[str] || (cache[str] = fn(str))
  }
}

isReserved

检测字符串是否以 $ 或者 _ 开头

// charCodeAt() 方法可返回指定位置的字符的 Unicode 编码
export function isReserved(str: string): boolean {
  const c = (str + '').charCodeAt(0)
  return c === 0x24 || c === 0x5f
}

charCodeAt

从传递进来的字母序列中找到缺失的字母并返回它。 如:fearNotLetter(“abce”) 应该返回 “d”。

function fearNotLetter(str) {
  //将字符串转为ASCII码,并存入数组
  let arr = []
  for (let i = 0; i < str.length; i++) {
    arr.push(str.charCodeAt(i))
  }
  for (let j = 1; j < arr.length; j++) {
    let num = arr[j] - arr[j - 1]
    //判断后一项减前一项是否为1,若不为1,则缺失该字符的前一项
    if (num != 1) {
      //将缺失字符ASCII转为字符并返回
      return String.fromCharCode(arr[j] - 1)
    }
  }
  return undefined
}
fearNotLetter('abce') // "d"

camelize

连字符转驼峰命名

const camelizeRE = /-(\w)/g
function camelize(str) {
  return str.replace(camelizeRE, function (_, c) {
    return c ? c.toUpperCase() : ''
  })
}
//ab-cd-ef ==> abCdEf
//使用记忆函数
const _camelize = cached(camelize)

hyphenate

驼峰命名转横线命名:拆分字符串,使用 - 相连,并且转换为小写

const hyphenateRE = /\B([A-Z])/g
function hyphenate(str) {
  return str.replace(hyphenateRE, '-$1').toLowerCase()
}
//abCd ==> ab-cd
//使用记忆函数
const _hyphenate = cached(hyphenate)

capitalize

字符串首位大写

function capitalize(str) {
  return str.charAt(0).toUpperCase() + str.slice(1)
}
// abc ==> Abc
//使用记忆函数
const _capitalize = cached(capitalize)

extend

将属性混合到目标对象中

function extend(to, _from) {
  for (const key in _from) {
    to[key] = _from[key]
  }
  return to
}

deepClone

  • 简单的深克隆
function deepClone(target) {
  return JSON.parse(JSON.stringify(target))
}

Array - unique

  • 基于 Set 简单实现
function unique(arr) {
  return [...new Set(arr)]
}

isNaN

检查数据是否是非数字值
原生的 isNaN 会把参数转换成数字(valueof),而 null、true、false 以及长度小于等于 1 的数组(元素为非 NaN 数据)会被转换成数字,这不是我想要的。Symbol 类型的数据不具有 valueof 接口,所以 isNaN 会抛出错误,这里放在后面,可避免错误

function _isNaN(value) {
  const type = typeof value
  return !(type === 'string' || type === 'number') || isNaN(v)
}

Array - max

求取数组中非 NaN 数据中的最大值

function max(arr) {
  arr = arr.filter((item) => !_isNaN(item))
  return arr.length ? Math.max.apply(null, arr) : undefined
}
//max([1, 2, '11', null, 'fdf', []]) ==> 11

Array - min

求取数组中非 NaN 数据中的最小值

function min(arr) {
  arr = arr.filter((item) => !_isNaN(item))
  return arr.length ? Math.min.apply(null, arr) : undefined
}
//min([1, 2, '11', null, 'fdf', []]) ==> 1

Profile picture

Personal blog by xg4.
Peace & Love.