本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
- 前言
大家好,我是若川。欢迎关注我的公众号若川视野,最近组织了源码共读活动,感兴趣的可以加我微信 ruochuan12 参与,已进行两个多月,大家一起交流学习,共同进步,很多人都表示收获颇丰。
想学源码,极力推荐之前我写的《学习源码整体架构系列》 包含jQuery
、underscore
、lodash
、vuex
、sentry
、axios
、redux
、koa
、vue-devtools
、vuex4
、koa-compose
、vue 3.2 发布
、vue-this
、create-vue
、玩具vite
等10余篇源码文章。
最近组织了源码共读活动,大家一起学习源码。于是搜寻各种值得我们学习,且代码行数不多的源码。
之前写了 Vue3
相关的两篇文章。
这篇写了如何学习 JavaScript 基础知识,推荐了很多书籍和学习资料,还有我的一些经验分享。
参加源码共读的读者反馈,TA 其实还是用着 Vue2
。能不能写篇 Vue2
基础工具函数。作为一名知识博主卑微号主,本着学我所学,为我所用,帮助他人的宗旨,于是写上了这篇文章。算是 Vue3
工具函数的姐妹篇。
阅读本文,你将学到:
1 | js复制代码1. Vue2 源码 shared 模块中的几十个实用工具函数 |
- 环境准备
2.1 读开源项目 贡献指南
打开 vue 仓库,
开源项目一般都能在 README.md
或者 .github/contributing.md 找到贡献指南。
而贡献指南写了很多关于参与项目开发的信息。比如怎么跑起来,项目目录结构是怎样的。怎么投入开发,需要哪些知识储备等。
我们可以在 项目目录结构 描述中,找到shared
模块。
shared
: contains utilities shared across the entire codebase.
README.md
和 contributing.md
一般都是英文的。可能会难倒一部分人。其实看不懂,完全可以可以借助划词翻译,整页翻译和谷歌翻译等翻译工具。再把英文加入后续学习计划。
本文就是讲 shared
模块,对应的文件路径是:vue/vue/src/shared
。
也可以用github1s
访问,速度更快。github1s vue/vue/src/shared
2.2 为了降低文章难度,直接学习打包后的源码
源代码的代码vue/vue/src/shared
,使用了Flow 类型,可能不太好理解。
为了降低文章难度,我们直接学习源码仓库中的打包后的 dist/vue.js 14行到379行。
当然,前面可能比较啰嗦。我可以直接讲
3. 工具函数
。但通过我上文的介绍,即使是初学者,都能看懂一些开源项目源码,也许就会有一定的成就感。
另外,面试问到被类似的问题或者笔试题时,你说看Vue2
源码学到的,面试官绝对对你刮目相看。
- 工具函数
打包后的 vue.js 14行到379行,接下来就是解释其中的这些方法。
3.1 emptyObject
1 | js复制代码/*! |
冻结对象。第一层无法修改。对象中也有判断是否冻结的方法。
1 | js复制代码Object.isFrozen(emptyObject); // true |
关于对象 API
推荐看之前我的文章 JavaScript 对象所有API解析
还可以看阮一峰老师的ES6 入门书籍 reflect
3.2 isUndef 是否是未定义
1 | js复制代码// These helpers produce better VM code in JS engines due to their |
3.3 isDef 是否是已经定义
JavaScript
中假值有六个。
1 | js复制代码false |
为了判断准确,Vue2 源码中封装了isDef
、 isTrue
、isFalse
函数来准确判断。
见名知意。
1 | js复制代码function isDef (v) { |
3.4 isTrue 是否是 true
见名知意。
1 | js复制代码function isTrue (v) { |
3.5 isFalse 是否是 false
见名知意。
1 | js复制代码function isFalse (v) { |
3.6 isPrimitive 判断值是否是原始值
判断是否是字符串、或者数字、或者 symbol
、或者布尔值。
1 | js复制代码/** |
3.7 isObject 判断是对象
因为 typeof null
是 ‘object’。数组等用这个函数判断也是 true
1 | js复制代码/** |
3.8 toRawType 转换成原始类型
Object.prototype.toString()
方法返回一个表示该对象的字符串。
ecma 规范,说明了这些类型。
1 | js复制代码/** |
3.9 isPlainObject 是否是纯对象
1 | js复制代码/** |
3.10 isRegExp 是否是正则表达式
1 | js复制代码function isRegExp (v) { |
3.11 isValidArrayIndex 是否是可用的数组索引值
数组可用的索引值是 0 (‘0’)、1 (‘1’) 、2 (‘2’) …
1 | js复制代码/** |
该全局 isFinite()
函数用来判断被传入的参数值是否为一个有限数值(finite number
)。在必要情况下,参数会首先转为一个数值。
1 | js复制代码isFinite(Infinity); // false |
3.12 isPromise 判断是否是 promise
1 | js复制代码function isPromise (val) { |
这里用 isDef
判断其实相对 isObject
来判断 来说有点不严谨。但是够用。
3.13 toString 转字符串
转换成字符串。是数组或者对象并且对象的 toString
方法是 Object.prototype.toString
,用 JSON.stringify
转换。
1 | js复制代码/** |
3.14 toNumber 转数字
转换成数字。如果转换失败依旧返回原始字符串。
1 | js复制代码/** |
3.15 makeMap 生成一个 map (对象)
传入一个以逗号分隔的字符串,生成一个 map
(键值对),并且返回一个函数检测 key
值在不在这个 map
中。第二个参数是小写选项。
1 | js复制代码/** |
3.16 isBuiltInTag 是否是内置的 tag
1 | js复制代码/** |
3.17 isReservedAttribute 是否是保留的属性
1 | js复制代码/** |
3.18 remove 移除数组中的中一项
1 | js复制代码/** |
splice
其实是一个很耗性能的方法。删除数组中的一项,其他元素都要移动位置。
引申:axios InterceptorManager
拦截器源码 中,拦截器用数组存储的。但实际移除拦截器时,只是把拦截器置为 null
。而不是用splice
移除。最后执行时为 null
的不执行,同样效果。axios
拦截器这个场景下,不得不说为性能做到了很好的考虑。因为拦截器是用户自定义的,理论上可以有无数个,所以做性能考虑是必要的。
看如下 axios
拦截器代码示例:
1 | js复制代码// 代码有删减 |
3.19 hasOwn 检测是否是自己的属性
1 | js复制代码/** |
3.20 cached 缓存
利用闭包特性,缓存数据
1 | js复制代码/** |
系统学习正则推荐老姚:《JavaScript 正则表达式迷你书》问世了!,看过的都说好。所以本文不会很详细的描述正则相关知识点。
3.21 camelize 连字符转小驼峰
连字符 - 转驼峰 on-click => onClick
1 | js复制代码/** |
3.22 capitalize 首字母转大写
首字母转大写
1 | js复制代码/** |
3.23 hyphenate 小驼峰转连字符
onClick => on-click
1 | js复制代码/** |
3.24 polyfillBind bind 的垫片
1 | js复制代码/** |
简单来说就是兼容了老版本浏览器不支持原生的 bind
函数。同时兼容写法,对参数的多少做出了判断,使用call
和apply
实现,据说参数多适合用 apply
,少用 call
性能更好。
如果对于call、apply、bind
的用法和实现不熟悉,可以查看我在面试官问系列中写的面试官问:能否模拟实现JS的call和apply方法
面试官问:能否模拟实现JS的bind方法
3.25 toArray 把类数组转成真正的数组
把类数组转换成数组,支持从哪个位置开始,默认从 0 开始。
1 | js复制代码/** |
3.26 extend 合并
1 | js复制代码/** |
3.27 toObject 转对象
1 | js复制代码/** |
3.28 noop 空函数
1 | js复制代码/* eslint-disable no-unused-vars */ |
3.29 no 一直返回 false
1 | js复制代码/** |
3.30 identity 返回参数本身
1 | js复制代码/** |
3.31 genStaticKeys 生成静态属性
1 | js复制代码/** |
3.32 looseEqual 宽松相等
由于数组、对象等是引用类型,所以两个内容看起来相等,严格相等都是不相等。
1 | js复制代码var a = {}; |
所以该函数是对数组、日期、对象进行递归比对。如果内容完全相等则宽松相等。
1 | js复制代码/** |
3.33 looseIndexOf 宽松的 indexOf
该函数实现的是宽松相等。原生的 indexOf
是严格相等。
1 | js复制代码/** |
3.34 once 确保函数只执行一次
利用闭包特性,存储状态
1 | js复制代码/** |
3.35 生命周期等
1 | js复制代码var SSR_ATTR = 'data-server-rendered'; |
- 最后推荐一些文章和书籍
这部分和Vue3工具函数文章一样,值得推荐,所以复制到这里。
先推荐我认为不错的JavaScript API
的几篇文章和几本值得读的书。
JavaScript 对象所有API解析 lxchuan12.gitee.io/js-object-a…
《JavaScript面向对象编程2》 面向对象讲的很详细。
我也是从小白看不懂书经历过来的。到现在写文章分享。
我看书的方法:多本书同时看,看相同类似的章节,比如函数。看完这本可能没懂,看下一本,几本书看下来基本就懂了,一遍没看懂,再看几遍,可以避免遗忘,巩固相关章节。当然,刚开始看书很难受,看不进。这些书大部分在微信读书都有,如果习惯看纸质书,那可以买来看。
这时可以看些视频和动手练习一些简单的项目。
比如:可以自己注册一个github
账号,分章节小节,抄写书中的代码,提交到github
,练习了才会更有感觉。
再比如 freeCodeCamp 中文在线学习网站 网站。看书是系统学习非常好的方法。后来我就是看源码较多,写文章分享出来给大家。
- 总结
本文通过查看 Vue2
源码中 shared
模块打包后的 dist/vue.js 14行到379行。源码也不是那么难,至少很多能看懂,比如工具函数。难可能是难在:不知道应用场景。
Vue2
工具函数命名很规范,比如:is
判断,to
转换,has
是否有,让开发者一眼就能看出函数语意。
这些函数也非常单一,基本一个函数只做一件事。
建议读者朋友把不熟悉的函数,动手写写,有助于巩固基础知识,查漏补缺。
最后可以持续关注我@若川。欢迎加我微信 ruochuan12 交流,参与 源码共读 活动,大家一起学习源码,共同进步。
关于 && 交流群
最近组织了源码共读活动,感兴趣的可以加我微信 ruochuan12 参与,长期交流学习。
作者:常以若川为名混迹于江湖。欢迎加我微信ruochuan12
。前端路上 | 所知甚少,唯善学。
关注公众号若川视野,每周一起学源码,学会看源码,进阶高级前端。
segmentfault
若川视野专栏,开通了若川视野专栏,欢迎关注~
掘金专栏,欢迎关注~
知乎若川视野专栏,开通了若川视野专栏,欢迎关注~
github blog,求个star
^_^~
本文转载自: 掘金