携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情
- 本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
- 这是源码共读的第2期,vue3工具函数。
前言
随着尤大官宣Vue3 在 2022 年 2 月 7 日 成为新的默认版本,学习vue3或者升级vue3已经成为老生常谈的话题。
正好最近公司有不少vue2项目要升级vue3,趁这次学习源码活动加深一下vue3工具函数的理解。
纸上得来终觉浅,绝知此事要躬行。下面探讨一下vue3源码工具函数,一起学以致用吧~
学习目标
- 学习如何调试vue3源码
- 理解vue3源码shared模块中的实用工具函数
- 学习源码中优秀代码和思想,尝试学以致用,投入到自己的项目中
前期准备
- 从贡献指南得知,运行环境要求如下
// 环境准备
node.js 版本16以上
pnpm 版本7以上
版本检测:node -v
pnpm -v
- 下载源码
git clone https://github.com/vuejs/vue-next.git
cd vue-next
// pnpm下载、淘宝镜像设置
npm i pnpm -g
pnpm config set registry https://registry.npmmirror.com
// 安装依赖
pnpm install
// 打包
pnpm build
- 工具函数路径/packages/shared/src/index.ts
源码调试
1.生成sourcemap调试代码,根据贡献指南的描述,可以在package.json中配置-s或--sourcemap来生成sourcemap,但是会导致打包速度慢,因此我们配置开发时生成sourcemap, 在package.json的script标签加入以下命令:
"dev:sourcemap":"node scripts/dev.js -s"
- 生成文件位置:packages\vue\dist\vue.global.js.map
2.安装live server插件创建本地服务
工具函数
1.EMPTY_OBJ 空对象
- 源码
export const EMPTY_OBJ: { readonly [key: string]: any } = __DEV__
? Object.freeze({})
: {}
- 源码理解:非生产环境返回冻结的空对象,否则返回空对象
- 拓展知识点:Object.freeze方法,冻结一个对象,使得该对象不能被修改,添加新属性,删除已有属性
const obj = {
a:1,
b:2,
c:{}
}
Object.freeze(obj)
obj.add = 3
obj.c.add = 3
console.log(obj)
- 用以上方法调试一下object.freeze方法,结果如下,可以看出Object.freeze是浅冻结
2.EMPTY_ARR
- 源码
export const EMPTY_ARR = __DEV__ ? Object.freeze([]) : []
// 测试代码如下
const arr = []
Object.freeze(arr)
arr.push('a')
arr.concat([obj])
- 源码理解:非生产环境返回冻结的空数组,否则直接返回空数组
- 尝试用push给冻结的数组添加新元素,报错如下
- concat操作虽然不报错,但也没变化
3.NOOP空函数
- 源码
export const NOOP = () => {}
- 源码理解:返回一个空函数,便于压缩代码跟函数判断
- 测试代码
const NOOP = () => {}
const noopObj = {
fun: NOOP
}
noopObj.add = function(){
console.log('add')
}
if(noopObj.add===NOOP){
console.log('pass')
}
4.NO函数一直返回false
- 源码
export const NO = () => false
- 源码理解 一直返回false,用处是压缩代码并一直返回false
5.isOn 判断是否以on开头
- 源码
const onRE = /^on[^a-z]/
export const isOn = (key: string) => onRE.test(key)
- 源码理解:利用正则判断传入值是否以小写字母
on开头,其中^在首部代表以什么开头,[^a-z]表示小写字母 - 测试代码
const onRE = /^on[^a-z]/
const isOn = (key) => onRE.test(key)
const isOnChange = isOn('onChange')?isOn('change'):'true'
- 调试结果
6. isModelListener函数
- 源码
export const isModelListener = (key: string) => key.startsWith('onUpdate:')
- 源码理解: 判断传入值是否以
onUpdate:开头,可以用来判断事件监听器 - 测试代码
const isModelListener = (key) => key.startsWith('onUpdate:')
const isOnChange = isModelListener('onUpdate')?isOn('ONchange'):'true'
- 测试结果
7.extend合并
- 源码
export const extend = Object.assign
- 源码理解:利用Object.assign合并对象,Object.assign的作用是将所有可枚举属性的值从一个或多个源对象(sources)分配到目标对象(target),并返回目标对象,不能转换null或者undefined
- 测试代码
const extend = Object.assign
const test = extend({},{a:1})
const obj2 = extend('','a')
const obj1 = extend(null,'a')
- 调试结果
8.remove 移除项
- 源码
export const remove = <T>(arr: T[], el: T) => {
const i = arr.indexOf(el)
if (i > -1) {
arr.splice(i, 1)
}
}
- 源码理解:移除数组中的指定值,该方法会改变源数组
- 测试代码
const testArr = ['a',1,'b','c']
remove(testArr,1)
remove(testArr,'d')
- 测试结果
9.hasOwn判断自身属性
- 源码
const hasOwnProperty = Object.prototype.hasOwnProperty
export const hasOwn = (
val: object,
key: string | symbol
): key is keyof typeof val => hasOwnProperty.call(val, key)
- 源码理解:利用
Object.prototype.hasOwnProperty判断自身是否有某个属性 - 测试代码
const hasOwnProperty = Object.prototype.hasOwnProperty
const hasOwn = (val,key) => hasOwnProperty.call(val, key)
const testOwn = hasOwn(obj,'d')?? 'null' // false
10.isArray 判断是否是数组
- 源码
export const isArray = Array.isArray
- 源码理解:利用Array.isArray判断是否是数组
- 测试代码
const isArray = Array.isArray
const isArr = isArray([])
const isArr1 = isArray('')
- 测试结果
总结
下载了vue3源码,并尝试分析了其中10个shared包的工具函数,学会了动手调试代码并尝试生成map调试代码以及可以借鉴源码压缩代码的书写方式,在项目开发中也可以适当抽取相应的工具函数,由于时间原因只分析了部分源码,但是掌握分析源码的方法比分析数量多更重要,希望能坚持源码学习,有不对的地方欢迎赐教喔~