22个Vue 源码中的工具函数

  发布时间:2025-11-05 08:47:53   作者:玩站小弟   我要评论
前言本次涉及的工具函数 1-16 在 Vue3 的源码中,路径是 core/packages/shared/src/index.ts。17-22 在 Vue2 的源码中,路径是 vue/src/sha 。

前言

本次涉及的个V工具工具函数 1-16 在 Vue3 的源码中,路径是源码 core/packages/shared/src/index.ts。

17-22 在 Vue2 的函数源码中,路径是个V工具 vue/src/shared/util.ts。

1、源码 EMPTY_OBJ 空对象const EMPTY_OBJ = __DEV__

?函数 Object.freeze({})

: {}

注意:

Object.freeze 只能浅冻结,如果属性是个V工具对象,对属性的源码属性的修改就无法冻结了

const obj = { name: 张三, info: { a: 1, b: 2

}

};Object.freeze(obj);obj.name = 李四;console.log(obj); // { name: 张三, info: { a: 1, b: 2 } }obj.info.a = 66;console.log(obj); // { name: 张三, info: { a: 66, b: 2 } }

源码中的使用:

可以看出基本都是作为初始化或者兜底使用,由此产生疑问:

使用的函数地方有的是 options,有的个V工具是 props,不同地方用同一个对象,源码不会有问题么?函数首先,很多初始化操作,个V工具后续都会重新赋值,源码EMPTY_OBJ 只是函数作为占位使用。其次,因为 Object.freeze 的原因,免费信息发布网无法修改 EMPTY_OBJ,所以任何引用这个对象的地方,都不会受到影响。为什么判断是 __DEV__(process.env.NODE_ENV !== production) 的时候才使用 Object.freeze?Object.freeze 更多的是 Vue 源码开发者在调试时使用,可以通过报错,防止对空对象操作,更快发现源码问题。也因此,开发环境最终会避免了对 EMPTY_OBJ 的赋值操作,所以在生产环境使用 Object.freeze 意义不大。2、EMPTY_ARR 空数组const EMPTY_ARR = __DEV__ ? Object.freeze([]) : []3、 NOOP 空函数const NOOP = () => {}

依旧作为兜底和占位使用:

4、 NO 永远返回 false 的函数const NO = () => false

源码中的使用:

5、isOn 判断字符串是不是 on 开头,并且 on 后首字母不是小写字母const onRE = /^on[^a-z]/;const isOn = (key) => onRE.test(key);// 示例isOn(onChange); // trueisOn(onchange); // falseisOn(on3change); // true6、类型判断const isArray = Array.isArray

const isFunction = (val) => typeof val === functionconst isString = (val) => typeof val === stringconst isSymbol = (val) => typeof val === symbolconst isObject = (val) => val !== null && typeof val === objectconst toTypeString = (value) => Object.prototype.toString.call(value)

const isMap = (val) => toTypeString(val) === [object Map]const isSet = (val) => toTypeString(val) === [object Set]const isDate = (val) => toTypeString(val) === [object Date]const isPlainObject = (val) => Object.prototype.toString.call(val) === [object Object]// isPlainObject 判断是不是普通对象(排除正则、数组、日期、new Boolean、企商汇new Number、new String 这些特殊的对象)

isObject([]) // trueisPlainObject([]) // falseconst isPromise = (val) => { return isObject(val) && isFunction(val.then) && isFunction(val.catch)

}7、 toRawType 提取数据原始类型const toRawType = (value) => { return Object.prototype.toString.call(value).slice(8, -1)

}// 示例toRawType(); StringtoRawType([]); Array

源码中的使用:

8、isIntegerKey 判断是不是数字型的字符串const isIntegerKey = (key) => isString(key) &&

key !== NaN &&

key[0] !== - && + parseInt(key, 10) === key;

// 例子:

isIntegerKey(a); // falseisIntegerKey(0); // trueisIntegerKey(011); // falseisIntegerKey(11); // trueisIntegerKey(-11); // falseisIntegerKey(11); // falseisIntegerKey(NaN); // false9、makeMap 将字符串分隔成 map,区分大小写,返回一个函数来判断 map 中是否含有某个 keyfunction makeMap(str, expectsLowerCase) { const map = Object.create(null); const list = str.split(,); for (let i = 0; i < list.length; i++) {

map[list[i]] = true;

} return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val];

}10、isReservedProp 是否是保留属性const isReservedProp = /*#__PURE__*/ makeMap(// the leading comma is intentional so empty string "" is also included,key,ref,ref_for,ref_key, + onVnodeBeforeMount,onVnodeMounted, + onVnodeBeforeUpdate,onVnodeUpdated, + onVnodeBeforeUnmount,onVnodeUnmounted);

// [, key, ref, ref_for, ref_key, onVnodeBeforeMount, onVnodeMounted, onVnodeBeforeUpdate, onVnodeUpdated, onVnodeBeforeUnmount, onVnodeUnmounted]

// 示例

isReservedProp(key); // trueisReservedProp(onVnodeBeforeMount); // trueisReservedProp(); // trueisReservedProp( ); // false

如果有 /*#__PURE__*/ 这个标志,说明他是纯函数,如果没有调用它,打包工具会直接通 tree-shaking 把它删除,减少代码体积。

11、 isBuiltInDirective 是否是内置指令const isBuiltInDirective = /*#__PURE__*/ makeMap( bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo

)12、 cacheStringFunction 将函数变为可缓存结果的函数const cacheStringFunction = (fn) => { const cache = Object.create(null); return ((str) => { const hit = cache[str]; return hit || (cache[str] = fn(str));

});

};13、 camelize & hyphenate 连字符与驼峰互转const camelizeRE = /-(\w)/g;const camelize = cacheStringFunction((str) => { return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ));

});// 清爽版const camelize = str => str.replace(camelizeRE, (_, c) => { return c ? c.toUpperCase() : ;

});// 举例:on-click-a => onClickAcamelize(on-click-a);const hyphenateRE = /\B([A-Z])/g;const hyphenate = cacheStringFunction((str) => str.replace(hyphenateRE, -$1).toLowerCase());// 清爽版const hyphenate = str => str.replace(hyphenateRE, -$1).toLowerCase();// 仿照 camelize 写法const hyphenate = str => str.replace(hyphenateRE, (_, c) => { return c ? `-${c.toLowerCase()}` : ;

});// 举例:onClickA => on-click-ahyphenate(onClickA);14、 hasChanged 判断是不是有变化const hasChanged = (value, oldValue) => value !== oldValue && (value === value || oldValue === oldValue);// 示例

hasChanged(1, 1); // falsehasChanged(1, 2); // truehasChanged(+0, -0); // falsehasChanged(NaN, NaN); // false// 场景:watch 监测值是不是变化了// 扩展 Object.is & ===Object.is(+0, -0); // false Object.is(NaN, NaN); // true+0 === -0 // trueNaN === NaN // false15、b2b信息网invokeArrayFns 执行数组里的函数const invokeArrayFns = (fns, arg) => { for (let i = 0; i < fns.length; i++) {

fns[i](arg);

}

};// 示例const arr = [ function(val){ console.log(val + 张三);

}, function(val){ console.log(val + 李四);

}, function(val){ console.log(val + 王五);

},

]

invokeArrayFns(arr, 我是:);

源码中的使用:

16、 toNumber 转数字const toNumber = (val) => {

const n = parseFloat(val); return isNaN(n) ? val : n;

};

toNumber(111); // 111toNumber(a111); // a111toNumber(11a11); // 11toNumber(NaN); // NaN// isNaN vs Number.isNaN// isNaN 判断是不是数字 is Not a Number// Number.isNaN 判断是不是 NaNisNaN(NaN); // trueisNaN(a); // trueNumber.isNaN(NaN); // trueNumber.isNaN(a); // false// Number.isNaN 的 polyfillif (!Number.isNaN) { Number.isNaN = function (n) { // 方法一 return (window.isNaN(n) && typeof n === number); // 方法二 利用只有 NaN 不跟自己相等的特性 return n !== n;

};

}17、isPrimitive 是否为原始数据function isPrimitive(value) { return ( typeof value === string || typeof value === number || typeof value === symbol || typeof value === boolean

)

}18、 isValidArrayIndex 是否为有效的数组下标,整数并且不是无穷大function isValidArrayIndex(val) { const n = parseFloat(String(val)) return n >= 0 && Math.floor(n) === n && isFinite(val)

}// isFinite 如果参数是 NaN,正无穷大或者负无穷大,会返回 false,其他返回 true19、bind 能兼容的bind函数function polyfillBind(fn, ctx) { 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, ctx) { return fn.bind(ctx)

}const bind = Function.prototype.bind ? nativeBind : polyfillBind20、 toArray 类数组转化为数组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、 once 只执行一次function once(fn) { let called = false

return function () { if (!called) {

called = true

fn.apply(this, arguments)

}

}

}22、 isNative 是否为原生系统函数function isNative(Ctor) { return typeof Ctor === function && /native code/.test(Ctor.toString())

}
  • Tag:

相关文章

  • 七彩虹GTX730显卡的性能与特点剖析(了解七彩虹GTX730显卡的卓越性能及特色功能)

    摘要:随着电子竞技的兴起和游戏图形需求的不断增加,显卡的性能成为了衡量电脑游戏表现的重要因素之一。而七彩虹GTX730显卡作为一款中端显卡,凭借其卓越的性能与特点,备受广大游戏爱好者的青...
    2025-11-05
  • 数据仓库的下一阶段该是什么?

    在大数据时代,大家都意识到数据已经成为了公司宝贵的资产,但如何让数据发挥价值,一直困扰着大家。数据技术人员需要长时间去理解某一个业务,业务人员也很难使用现代化数据分析工具赋能业务。那么,如何让公司数据
    2025-11-05
  • 学习 Java 中最困难的部分以及如何克服它们

    今天,我们将看看 Java 编程基础中一些最难的领域,试图了解为什么很多人觉得它们很困难,以及是否有什么需要你做的。1. 泛型Java 中的泛型是具有参数的类型。创建泛型类型时,你不仅要指定类型,还要
    2025-11-05
  • 一份不可多得的 TypeScript 学习笔记

    Hi,我是前端人,今日与君共勉!本篇文章主要介绍 typeScript 中类的定义、类的继承、类中成员修饰符等内容。typeScript 中的类与 ES6 中的类非常相似,如果不知道 ES6 中的类,
    2025-11-05
  • 拯救者BIOS降级教程(降级BIOS,让拯救者重获新生)

    摘要:在使用拯救者电脑的过程中,由于各种原因,我们可能会遇到一些BIOS版本不兼容、无法正常启动等问题。为了解决这些问题,我们需要学习如何进行BIOS降级。本文将为大家详细介绍拯救者BI...
    2025-11-05
  • 网易传媒数据管治建设实践

    全文将围绕以下四部分展开:传媒业务介绍数仓建设演进数据管治体系数据管治展望01传媒业务介绍1. 业务介绍​网易从门户网站到新闻客户端,我们的目标是让用户在短时间内去中心化地获取内容信息。整体的业务流程
    2025-11-05

最新评论