VUE源码工具函数分析

  • 源码中使用了typescript语法 export导出 本地练习时因为没有配置环境先注释掉
// 判断当前环境
    // 1.1inBrowser: 检测当前宿主环境是否是浏览器
    // 通过判断 `window` 对象是否存在即可
    // export const inBrowser = typeof window !== 'undefined'
    const inBrowser = typeof window !== 'undefined'
    console.log(inBrowser); // true
    console.log(typeof window); // object

    // 1.2 hasProto:检查当前环境是否可以使用对象的 __proto__ 属性
    // 一个对象的 __proto__ 属性指向了其构造函数的原型
    // 从一个空的对象字面量开始沿着原型链逐级检查。
    // export const hasProto = '__proto__' in {}
    const hasProto = '__proto__' in {}
    console.log(hasProto); // true

    // 2.1 获取当浏览器的user Agent
    // toLowerCase目的是 为了后续的各种环境检测
    // export const UA = inBrowser && window.navigator.userAgent.toLowerCase()
    const UA = inBrowser && window.navigator.userAgent.toLowerCase()
    console.log(UA); // mozilla/5.0 (windows nt 10.0; wow64) applewebkit/537.36 (khtml, like gecko) chrome/68.0.3440.106 safari/537.36

    // 2.2 IE浏览器判断
    // 解析:使用正则去匹配 UA 中是否包含'msie'或者'trident'这两个字符串即可判断是否为 IE 浏览器
    // export const isIE = UA && /msie|trident/.test(UA)
    const isIE = UA && /msie|trident/.test(UA);
    console.log(isIE);  // false   用的chrome

    // 2.3 IE9| Edge | Chrome 判断
    export const isIE9 = UA && UA.indexOf('msie 9.0') > 0
    export const isEdge = UA && UA.indexOf('edge/') > 0
    export const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge

    // 字符串操作
    // 3.1 isReserved:检测字符串是否以 $ 或者 _ 开头
    // charCodeAt() 方法可返回指定位置的字符的 Unicode 编码
    // export function isReserved (str: string): boolean { // TS语法
    // const c = (str + '').charCodeAt(0)
    // return c === 0x24 || c === 0x5F
    // }
    // 解析: 获得该字符串第一个字符的unicode,然后与 0x24 和 0x5F 作比较。
    function isReserved (str) {
    const c = (str + '').charCodeAt(0)
    return c === 0x24 || c === 0x5F
    }
    console.log(isReserved('_abc')); // true
    console.log(isReserved('$abc')); // true
    console.log(isReserved('abc')); // false

    // 3.2 camelize: 连字符转驼峰
    // const camelizeRE = /-(\w)/g
    // export const camelize = cached((str: string): string => {
    // return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
    // })
    //解析: 定义正则表达式:/-(\w)/g,用来全局匹配字符串中 中横线及连字符后的一个字符。
    //若捕获到,则将字符以toUpperCase大写替换,否则以''替换。 如:camelize('aa-bb') // aaBb
    const camelizeRE = /-(\w)/g
    const camelize = cached((str) => {
    return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
    })
    console.log(camelize('abc-asd')); // cached暂未定义
    // hyphenate:驼峰转连字符
    const hyphenateRE = /\B([A-Z])/g
    export const hyphenate = cached((str: string): string => {
    return str.replace(hyphenateRE, '-$1').toLowerCase()
    })


    // 3.3 toString: 将给定变量的值转换为 string 类型并返回
    // export function toString (val: any): string {
    // return val == null
    //     ? ''
    //     : typeof val === 'object'
    //     ? JSON.stringify(val, null, 2) // 使用2个空格缩进
    //     : String(val)
    // }
    function toString (val) {
    return val == null
        ? ''
        : typeof val === 'object'
        ? JSON.stringify(val, null, 2) // 使用2个空格缩进
        : String(val)
    }
    console.log(toString({})) // '{}'
    console.log(toString(null)) // ''
    console.log(toString(123)) // '123'

    // 3.3.2 mergeHook: 合并生命周期选项
    // 多元运算符的运用 换行对其 方便读写
    function mergeHook (
    parentVal: ?Array<Function>,
    childVal: ?Function | ?Array<Function>
    ): ?Array<Function> {
    return childVal
        ? parentVal
            ? parentVal.concat(childVal)
            : Array.isArray(childVal)
                ? childVal
                : [childVal]
        : parentVal
    }

    // 3.4 capitalize:首字符大写
    // 忽略cached
    export const capitalize = cached((str: string): string => {
    return str.charAt(0).toUpperCase() + str.slice(1)
    })

    // 4. 类型判断
    // 4.1 isPrimitive: 判断变量是否为原型类型
    export function isPrimitive (value: any): boolean %checks {
    return (
        typeof value === 'string' ||
        typeof value === 'number' ||
        // $flow-disable-line
        typeof value === 'symbol' ||
        typeof value === 'boolean'
    )
    }

    // 4.2 isRegExp: 判断变量是否为正则对象。
    // 使用 Object.prototype.toString 与 '[object RegExp]' 做全等对比。
    export function isRegExp (v: any): boolean {
    return _toString.call(v) === '[object RegExp]'
    }

    // 4.3 isValidArrayIndex: 判断变量是否含有效的数组索引
    export 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)
    }

    // 4.4 isObject: 区分对象和原始值
    export function isObject (obj: mixed): boolean %checks {
    return obj !== null && typeof obj === 'object'
    }

    // 5.Vue中的闭包使用
    // 5.1 makeMap():判断一个变量是否包含在传入字符串里
    export function makeMap (
    str: string,
    expectsLowerCase?: boolean
    ): (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 expectsLowerCase
        ? val => map[val.toLowerCase()]
        : val => map[val]
    }
    // 定义一个对象map
    // 将 str 分隔成数组并保存到 list 变量中 遍历list,并以list中的元素作为 map 的 key,将其设置为 true
    // 返回一个函数,并且如果expectsLowerCase为true的话,小写map[key]:
    let isLaugh = makMap('嘻嘻,哈哈',true); 
    //设定一个检测是否为我的名字的方法,第二个参数不区分大小写
    isLaugh('嘻嘻')  // true
    isLaugh('哈哈')  // true
    isLaugh('呵呵')  // false

    // 5.2 once:只调用一次的函数
    // 以called作为回调标识符。调用此函数时,called标示符改变,下次调用就无效了
    export function once (fn: Function): Function {
    let called = false
    return function () {
        if (!called) {
        called = true
        fn.apply(this, arguments)
        }
    }
    }

    // 5.3 cache:创建一个缓存函数
    /**
    * Create a cached version of a pure function.
    */
    export function cached<F: Function> (fn: F): F {
    const cache = Object.create(null)
    return (function cachedFn (str: string) {
        const hit = cache[str]
        return hit || (cache[str] = fn(str))
    }: any)
    }
    // const cache = Object.create(null)创建纯函数是为了防止变化(纯函数的特性:输入不变则输出不变)。

    // 多类型的全等判断
    // looseEqual: 判断两个值是否相等  结合注释很容易看懂
    export function looseEqual (a: any, b: any): boolean {
    // 当 a === b 时,返回true
    if (a === b) return true
    // 否则进入isObject判断
    const isObjectA = isObject(a)
    const isObjectB = isObject(b)
    // 判断是否都为Object类型
    if (isObjectA && isObjectB) {
        try {
        // 调用 Array.isArray() 方法,再次进行判断
        // isObject 不能区分是真数组还是对象(typeof)
        const isArrayA = Array.isArray(a)
        const isArrayB = Array.isArray(b)
        // 判断是否都为数组
        if (isArrayA && isArrayB) {
            // 对比a、bs数组的长度
            return a.length === b.length && a.every((e, i) => {
            // 调用 looseEqual 进入递归
            return looseEqual(e, b[i])
            })
        } else if (!isArrayA && !isArrayB) {
            // 均不为数组,获取a、b对象的key集合
            const keysA = Object.keys(a)
            const keysB = Object.keys(b)
            // 对比a、b对象的key集合长度
            return keysA.length === keysB.length && keysA.every(key => {
            //长度相等,则调用 looseEqual 进入递归
            return looseEqual(a[key], b[key])
            })
        } else {
            // 如果a、b中一个是数组,一个是对象,直接返回 false
            /* istanbul ignore next */
            return false
        }
        } catch (e) {
        /* istanbul ignore next */
        return false
        }
    } else if (!isObjectA && !isObjectB) {
        return String(a) === String(b)
    } else {
        return false
    }
    }




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值