Vue 2.6源码学习(08)-vue2工具函数

142 阅读3分钟

本文参加了由公众号@若川视野 发起的每周源码共读活动,  点击了解详情一起参与。

1.代码目录 src/shared/util.js

image.png

2.工具函数

主要分4大类:基本类型检测,引用类型的判断,类型转换,工具函数

2.1 基本类型检测

// These helpers produce better VM code in JS engines due to their

// explicitness and function inlining.

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

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

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

export function isFalse (v: any){
    return v === false
}
//检测是否式基本类型
/**
* Check if value is primitive.
*/

export function isPrimitive (value){
    return (
        typeof value === 'string' ||
        typeof value === 'number' ||
        // $flow-disable-line
        typeof value === 'symbol' ||
        typeof value === 'boolean'
    )
}

2.2 引用类型的判断

2.2.1 引用类型判断

export function isObject (obj){
    return obj !== null && typeof obj === 'object'
}
/**
* Get the raw type string of a value, e.g., [object Object].
*/
//使用Object.prototype.toString的方法判断类型
const _toString = Object.prototype.toString

export function toRawType (value){
    return _toString.call(value).slice(8, -1)
}
//toRawType([])
//'Array'
//toRawType({})
//'Object'
/**
* Strict object type check. Only returns true
* for plain JavaScript objects.
*/

export function isPlainObject (obj){
    return _toString.call(obj) === '[object Object]'
}
//判断正则类型
export function isRegExp (v){
    return _toString.call(v) === '[object RegExp]'
}

2.2.2 其他类型的判断

/**
* Check if val is a valid array index.
*/
//判断是否式数组的下标
export function isValidArrayIndex (val: any): boolean {
    const n = parseFloat(String(val))
    return n >= 0 && Math.floor(n) === n && isFinite(val)
}

//promise的类型判断,判断是否有then方法和catch方法
export function isPromise (val: any): boolean {
    return (
        isDef(val) &&
        typeof val.then === 'function' &&
        typeof val.catch === 'function'
    )
}

扩展:isFinite sFinite() 函数用于检查其参数是否是无穷大,也可以理解为是否为一个有限数值(finite number)。 提示:  如果参数是 NaN,正无穷大或者负无穷大,会返回 false,其他返回 true。

2.3 类型转换

//转换成字符串,如果是引用类型使用JSON.stringify转换
//_toString = Object.prototype.toString
export function toString (val){

    return val == null
    ? ''
    : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)
        ? JSON.stringify(val, null, 2)
        : String(val)
}
/**
* Convert an input value to a number for persistence.
* If the conversion fails, return original string.
*/

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

2.4 工具函数

/**
* Make a map and return a function for checking if a key
* is in that map.
*/
//makeMap方法使用闭包,保存一个map,下次可以调用检查key是否在map中
export function makeMap (str,expectsLowerCase){

    const map = Object.create(null)

    const list: Array<string> = str.split(',')
        for (let i = 0; i < list.length; i++) {
            map[list[i]] = true
        }
        return expectsLowerCase
                ? val => map[val.toLowerCase()]
                : val => map[val]
}

/**
* Check if a tag is a built-in tag.
*/

export const isBuiltInTag = makeMap('slot,component', true)
//isBuiltInTag(component) true
//isBuiltInTag('z')  undefined
/**
* Check if an attribute is a reserved attribute.
*/
export const isReservedAttribute = makeMap('key,ref,slot,slot-scope,is')

2.4.2 删除数组中的元素

/**
* Remove an item from an array.
*/
export function remove (arr){
    if (arr.length) {
        const index = arr.indexOf(item)
        if (index > -1) {
            return arr.splice(index, 1)
        }
    }
}

2.4.3 判断是否是对象的本身属性,排除原型上的属性

/**
* Check whether an object has the property.
*/

const hasOwnProperty = Object.prototype.hasOwnProperty
export function hasOwn (obj, key){
    return hasOwnProperty.call(obj, key)
}

2.4.4 cache缓存,利用闭包缓存数据

/**
* Create a cached version of a pure function.
*/

export function cached(fn){
    const cache = Object.create(null)
    return (function cachedFn (str) {
        const hit = cache[str]
        //若存在hit则返回hit,没有则缓存
        return hit || (cache[str] = fn(str))
    })
}

2.4.5 bind的兼容写法

/* istanbul ignore next */

function polyfillBind (fn, ctx){
    function boundFn (a) {
        const l = arguments.length
        //根据参数的长度来使用apply或者call
        return l
                ? l > 1
                ? fn.apply(ctx, arguments)
                : fn.call(ctx, a)
                : fn.call(ctx)
    }
    boundFn._length = fn.length
    return boundFn
}

function nativeBind (fn, ctx){
    return fn.bind(ctx)
}
//函数原型上有bind方法则使用原有的bind,否则使用polyfillBind
export const bind = Function.prototype.bind
                    ? nativeBind
                    : polyfillBind

2.4.6 once函数

/**
* Ensure a function is called only once.
*/
export function once (fn: Function): Function {
    let called = false
    return function () {
    //利用闭包的特性,保存一个标识,当called=true时表示已经调用过回调函数
        if (!called) {
            called = true
            fn.apply(this, arguments)
        }
    }
}

小结

  • 熟悉了vue中的类型检查和类型转换,
  • 熟悉了闭包的特性
  • 了解了一些之前不知道的方法,如isFinite