22个Vue 源码中的工具函数

news2024/12/23 11:00:07

前言

在 vue 源码中,封装了很多工具函数,学习这些函数,一方面学习大佬们的实现方式,另一方面是温习基础知识,希望大家在日常工作中,简单的函数也可以自己封装,提高编码能力。

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

17-22 在 Vue2 的源码中,路径是 vue/src/shared/util.ts。

1、 EMPTY_OBJ 空对象

 
const EMPTY_OBJ = __DEV__  ? Object.freeze({})  : {}

注意:
Object.freeze 只能浅冻结,如果属性是对象,对属性的属性的修改就无法冻结了

 
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,有的是 props,不同地方用同一个对象,不会有问题么?
    首先,很多初始化操作,后续都会重新赋值,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'); // true

6、类型判断

 
const isArray = Array.isArray
const isFunction = (val) => typeof val === 'function'const isString = (val) => typeof val === 'string'const isSymbol = (val) => typeof val === 'symbol'const isObject = (val) => val !== null && typeof val === 'object'const 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('');  'String'toRawType([]);  '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'); // false

9、makeMap 将字符串分隔成 map,区分大小写,返回一个函数来判断 map 中是否含有某个 key

 
function 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 // false

15、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'); // 'a111'toNumber('11a11'); // '11'toNumber(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,其他返回 true

19、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 : polyfillBind

20、 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())}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/59446.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣(LeetCode)130. 被围绕的区域(C++)

dfs 只有和边界相连的 OOO 不会被 XXX 包围。遍历边界&#xff0c;搜索边界 OOO 的连通块&#xff0c;标记这些连通块。最后一次遍历矩阵&#xff0c;将标记的格子改回 OOO &#xff0c;其他格子改成 XXX &#xff0c;即为所求。 提示 : 可以用数组标记连通块&#xff0c;也可…

Java基于springboot+vue药店实名制买药系统 前后端分离

开发背景和意义 药品一直以来在人类生活中扮演着非常重要的角色&#xff0c;随着时代的发展&#xff0c;人们基本已经告别了那个缺医少药的年代&#xff0c;各大药房基本随处可以&#xff0c;但是很多时候因为没有时间或者在药店很难找到自己想要购买的药品&#xff0c;所以很…

元宇宙产业委叶毓睿:狂欢过后,万众期待的元宇宙怎么样了?

叶毓睿&#xff08;王学民/摄&#xff09; 自元宇宙出现在大众视野&#xff0c;大众对元宇宙的好奇和探索&#xff0c;从来没有停止过。当元宇宙的热度逐渐下降&#xff0c;我们不禁想要知道&#xff0c;狂欢过后&#xff0c;万众期待的元宇宙怎么样了&#xff1f; 近日&#x…

【吴恩达机器学习笔记】十一、聚类

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4e3;专栏定位&#xff1a;为学习吴恩达机器学习视频的同学提供的随堂笔记。 &#x1f4da;专栏简介&#xff1a;在这个专栏&#xff0c;我将整理吴恩达机器学习视频的所有内容的笔记&…

算法刷题入门线性表|单调栈

一、概念 1、栈的定义 栈 是仅限在 一端 进行 插入 和 删除 的 线性表。 栈 又被称为 后进先出 (Last In First Out) 的线性表&#xff0c;简称 LIFO 。 2、栈顶 栈 是一个线性表&#xff0c;我们把允许 插入 和 删除 的一端称为 栈顶。 3、栈底 和 栈顶 相对&#xff0c;另一端…

java计算机毕业设计ssm软件学院社团管理系统l62lq(附源码、数据库)

java计算机毕业设计ssm软件学院社团管理系统l62lq&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#…

[附源码]计算机毕业设计基于SpringBoot+Vue的健身房会员系统的设计与实现

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Linux系统( Centos 7) 配置与管理Apache服务器实例详细步骤

Linux系统&#xff08; Centos 7&#xff09; 配置与管理Apache服务器实例详细步骤 服务器centos7-1 1.配置网络。 [rootcentos7 ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens33 TYPEEthernet PROXY_METHODnone BROWSER_ONLYno BOOTPROTOstatic DEFROUTEyes IPV…

【WPF】附加事件

【WPF】附加事件什么是附加事件附加事件用法Microsoft 官方文档附加事件案例定义自定义控件注册使用附加事件什么是附加事件 Microsoft 官方概述&#xff1a;   附加事件可用于在非元素类中定义新的 路由事件 &#xff0c;并在树中的任何元素上引发该事件。 为此&#xff0c;…

【WebRTC】拥塞控制 GCC 类图

GoogCcNetworkController : 整个 congestion_controller 模块的中心类&#xff0c;是对外的接口 AcknowledgedBitrateEstimatorInterface AcknowledgedBitrateEstimator : 估算当前的吞吐量。 BitrateEstimator : 使用滑动窗口 卡尔曼滤波计算当前发送吞吐量。 RobustThro…

【Android App】实战项目之仿拼多多的直播带货(附源码和演示 超详细必看)

需要源码请点赞关注收藏后评论区留言私信~~~ 近年来电商业态发生了不小的改变&#xff0c;传统的电商平台把商品分门别类&#xff0c;配上精美的图文说明供消费者挑选&#xff0c;新潮的电商平台则请来明星网红&#xff0c;开启直播秀向广大粉丝推销商品&#xff0c;往往一场直…

微服务应对雪崩的容错方案

引言 书接上篇 微服务绕不过的坎-服务雪崩 &#xff0c;玩微服务不可避免的问题&#xff1a;服务雪崩&#xff0c;那为了应付服务雪崩问题&#xff0c;需要做啥预防性操作呢&#xff1f;答案是&#xff1a;做好容错保护 容错方案 前面说了&#xff0c;要防止雪崩的扩散&…

[附源码]计算机毕业设计springboot疫情期间小学生作业线上管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Android自定义视图

View 自定义视图主要涉及四个方面&#xff1a;绘图、交互、性能和封装 绘图 主要涉及两个对象&#xff1a;画布&#xff08;Canvas&#xff09;和画笔&#xff08;Paint&#xff09;&#xff0c;画布主要解决画什么的问题&#xff0c;在画布上可以绘制各种各样的图形&#x…

《CTFshow - Web入门》04. Web 31~40

Web 31~40web31知识点题解web32知识点题解web33知识点题解web34知识点题解web35知识点题解web36知识点题解web37知识点题解web38知识点题解web39知识点题解web40知识点题解web31 知识点 这里依旧可以用到 web29 的方法&#xff1a; 嵌套eval逃逸参数 当然&#xff0c;能多学…

# 智慧社区管理系统-基础信息管理-06抄表管理

一后端 1:entity package com.woniu.community.entity;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;Data AllArgsConstructor NoArgsConstructor public class Records {private int id;private int typeId;private Double num…

博安生物更新招股书:上半年亏1.5亿 绿叶制药与建银聚源是股东

雷递网 雷建平 12月3日山东博安生物技术股份有限公司&#xff08;简称&#xff1a;“博安生物”&#xff09;日前再次递交招股书&#xff0c;并更新招股书&#xff0c;准备在香港上市。上半年期内亏损1.53亿元博安生物是绿叶制药集团的附属公司&#xff0c;于2013年成立&#x…

远程桌面树莓派【内网穿透】

本篇文章主要分享如何在公网环境下&#xff0c;远程桌面连接家里的树莓派。 远程桌面环境&#xff0c;我们选择通过XRDP来实现&#xff0c;它内部使用的是windows远程桌面的协议。 而由于现在普遍处于大内网环境&#xff0c;绝大部分人都没有公网IP&#xff0c;所以我们这里用…

(9)点云数据处理学习——Global registration(全局注册)

1、主要参考 &#xff08;1&#xff09;官网的地址 Global registration — Open3D 0.16.0 documentation 2、作用和原理 2.1个人理解 PS理解&#xff1a;&#xff08;1&#xff09;ICP的作用是&#xff0c;2个点云数据在初步转换关系&#xff08;已知不精确&#xff09;的…

【关系抽取】TPLinker:单阶段联合抽取,并解决暴漏偏差

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…