第24期 | vue2工具函数

172 阅读5分钟

读源码

1.是否是空对象

export const emptyObject = Object.freeze({})

object.freeze()方法可以冻结一个对象,一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze()返回和传入的参数相同的对象。

可以用在vue中,对于只是数据展示,没有任何动态场景下,可以用object.freeze()对数据不做响应化处理。

2.是否是未定义

export function isUndef (v) {
  return v === undefined || v === null
}

3.是否已定义

export function isDef (v) {
  return v !== undefined && v !== null
}

4.是否为true

export function isTrue (v){
  return v === true
}

5.是否为false

export function isFalse (v) {
  return v === false
}

6.是否是原型类型

基本类型(基本数值、基本数据类型)是一种既非对象也无方法的数据。在 JavaScript 中,共有7种基本类型:stringnumberbigintbooleannullundefinedsymbol (ECMAScript 2016新增)。

image.png

export function isPrimitive (value){
  return (
    typeof value === 'string' ||
    typeof value === 'number' ||
    typeof value === 'symbol' ||
    typeof value === 'boolean'
  )
}

7.获取值的原始类型

// 和利用Object.prototype.toString()判读数据类型是一样的味道
const _toString = Object.prototype.toString
export function toRawType (value: any): string {
  return _toString.call(value).slice(8, -1)
}

8. 是否是可用的数组索引值

export function isValidArrayIndex (val) {
  const n = parseFloat(String(val))
  return n >= 0 && Math.floor(n) === n && isFinite(val)
}

parseFloat: developer.mozilla.org/zh-CN/docs/…

isFinite: developer.mozilla.org/zh-CN/docs/…

9.判断是否是promise

export function isPromise (val): boolean {
  return (
    isDef(val) &&
    typeof val.then === 'function' &&
    typeof val.catch === 'function'
  )
}

10.转为string

export function toString (val){
  return val == null
    ? ''
    : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)
      ? JSON.stringify(val, null, 2)
      : String(val)
}

developer.mozilla.org/zh-CN/docs/…

11.转化为数字,如果不能则返回原值

export function toNumber (val) {
  const n = parseFloat(val)
  return isNaN(n) ? val : n
}

12.判断某字符是否存在另一组字符里面

export function makeMap(str:string,expectLowerCase?:booleam):(key:string) => true|void{
  const map = Object.create(null)
  const list:Array<string> = str.split(',')
  for(let i = 0; i<list.length;i++){
    map[list[i]] = true
  }
  return expectLowerCase 
    ? val => map[val.toLowerCase()]
    : val => map[val]
}

这个方法作用类似于string的includes方法,判断下一个字符串是否存在另一个存在,

13.删除数组中的指定某一项

  export function remove(arr: Array<any>,item:any): Array<any> | void {
      if(arr.length){
          const index = arr.indexOf(item)
          if(index > -1){
              return arr.splice(index,1)
          }
      }
  }

14.判断是否是自己的属性

 const hasOwnProperty = Object.prototype.hasOwnProperty
  export function hasOwn(obj:Object|Array<*>,key:string):Boolean{
      return hasOwnProperty.call(obj,key)
  }

15.创建纯函数的缓存版本。

// 可以避免多次计算,做到缓存的效果
function cached(fn){
  var cache = Object.create(null)
  return (function cachedFn(str){
          var hit = cache[str]
        return hit || (cache[str] = fn(str))
    })       
}

16.连字符转小驼峰

var camelizeRE = /-(\w)/g
var camelize = cached(function(str){
    return str.replace(camelizeRE,function(-,c){return c ? c.toUpperCase(): ''})
})

17.首字母转换为大写

export const capitalize = cached((str:string):string => {
    return str.charAt(0).toUpperCase() + str.slice(1)
})

18.将小驼峰转换成连字符

const hyphenateRE = /\B([A-Z])/g
export const hyphenate = caches((str:string):string => {
    return str.replace(hyphenateRE,'-$1').toLowerCase()
})

19.兼容了老版本浏览器不支持原生的 bind 函数

function polyfillBind(fn: Function,ctx:Object):Function {
    function boundFn(a){
        const l = arguments.length
        return l
            ? l > 1
                ? fn.apply(ctx,arguments)
                : fn.call(ctx,a)
            : fn.call(ctx)
    }
    boundFn._length = fn.length
    return boundFn
}

function nativeBind(fn: Function,ctx:Object):Function{
    return fn.bind(ctx)
}

export const bind = Function.prototype.bind
    ? nativeBind
    : polyfillBind

20.类数组转换为数组

function toArray(list,start){
    start = start || 0
    let i = list.length - start
    const ret =  new Array(i)
    while(i--){
        ret[i] = list[i+start]
    }
    return ret
}

21.将属性混合到目标对象中

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

22.将一组对象合并为一个对象

function toObject(arr){
    const res = {}
    for(let i = 0; i < arr.length; i++){
        if(arr[i]){
            extend(res,arr[i])
        }
    }
    return res
}

23.生成包含来自编译器模块的静态键的字符串

function genStaticKeys(modules){
    return modules.reduce((keys,m) => {
        return keys.concat(m.staticKeys || [])
    },[]).join('.')
}

24.是否宽松相等

// 对于时间,数组,对象具有相同内容就认为相等,时间通过时间戳来判断,
// 对象和数组需要递归到最里层数据进行判断
function looseEqual(a,b){
    if(a === b) return true
    const isObjectA = isObject(a)
    const isObjectB = isObject(b)
    if(isObjectA && isObjectB){
        try{
            const isArrayA = Array.isArray(a)
            const isArrayB = Array.isArray(b)
            if(isArrayA && isArrayB){
                return a.length === b.length && a.every((e,i) => {
                    return looseEqual(e,b[i])
                })
            }else if( a instanceof Date && b instanceof Date){
                return a.getTime() === b.getTime()
            }else if(!isArrayA && !isArrayB){
                const keysA = Object.keys(a)
                const keysB = Object.keys(b)
                return keysA.length === keysB.length && keysA.every(key => {
                    return looseEqual(a[key],b[key])
                })
            }else{
                return false
            }
        }
        catch(e){
            return false
        }
    }else if(!isObjectA && !isObjectB){
        return String(a) === String(b)
    }else{
        return false
    }
}

25.返回第一个索引,在该索引处可以在数组中找到大致相等的值(如果值是普通对象,则数组必须包含相同形状的对象),如果不存在,则返回-1

function looseIndexOf(arr,val){
    for(let i = 0; i < arr.length; i++){
        if(looseEqual(arr[i],val)) return i
    }
    return -1
}

26.函数只执行一次

function once(fn){
    let called = false
    return function() {
        if(!called){
            called = true
            fn.apply(this,arguments)
        }
    }
}

收获

这篇文章最大的收获大概是看到了这个活动对我而言很重要的一个意义,这段时间觉得自己好菜,一直想努力去补,但是总有一种无从下手的感觉,在这个期间,我又想过去看css,去看了张鑫旭大佬的css世界,看的时候感觉哪哪都很厉害,但是看的时候也没有什么重点去看,也很着急,也没有看到效果,也有去想补一补js基础,去看红皮书,也是一样的结果,心里也很浮躁,觉得那那都不会,但是缺静不下来心去学,好像缺的东西太多了,不知道从哪里补起来,这篇文章是我2月初就写了一半,但是没有写完也是因为自己当时有换工作的打算,着急去看面试题,然后放下了,然后就是这段很长时间浮躁的过程,什么也没有长进,这周想着把这篇补齐,坐下来看这些小小的代码,上下连贯性不是很强,就算我心情浮躁,看一个小时就去干其他事情,我也可以收获两个小工具函数的点。剩下这半篇我也差不多花了快一天的时间,但是说不像前几周,好像一点也做不来了,给这篇收尾的过程中,看代码看文档中推荐的博文,也是有目的性的去看,比我自己盲目的去补某一个方面的知识点更有成效。接下来的时间了,继续坚持,慢慢静下来心来,参与进来,慢慢积累