发表时间:2022-03-26来源:网络
大家好,我是若川。最近组织了源码共读活动,感兴趣的可以加我
想学源码,极力推荐之前我写的《学习源码整体架构系列》jQuery、underscore、lodash、vuex、sentry、axios、redux、koa、vue-devtools、vuex4、koa-compose、vue-next-release、vue-this、create-vue、玩具vite等10余篇源码文章。
本文仓库 vue-analysis,求个star^_^[1]
最近组织了源码共读活动
之前写了 Vue3 相关的两篇文章。
初学者也能看懂的 Vue3 源码中那些实用的基础工具函数
这篇写了如何学习 JavaScript 基础知识,推荐了很多书籍和学习资料,还有我的一些经验分享。
Vue 3.2 发布了,那尤雨溪是怎么发布 Vue.js 的?
参加源码共读的读者反馈,TA 其实还是用着 Vue2。能不能写篇 Vue2 基础工具函数。作为一名知识博主卑微号主,本着学我所学,为我所用,帮助他人的宗旨,于是写上了这篇文章。算是 Vue3 工具函数的姐妹篇,本文和这篇文章会有类似的地方。
阅读本文,你将学到:
1. Vue2 源码 shared 模块中的几十个实用工具函数 2. 如何学习源码中优秀代码和思想,投入到自己的项目中 3. 如何学习 JavaScript 基础知识,会推荐很多学习资料 4. 我的一些经验分享 5. 等等打开 vue 仓库[2], 开源项目一般都能在 README.md 或者 .github/contributing.md[3] 找到贡献指南。
而贡献指南写了很多关于参与项目开发的信息。比如怎么跑起来,项目目录结构是怎样的。怎么投入开发,需要哪些知识储备等。
我们可以在 项目目录结构[4] 描述中,找到shared模块。
shared: contains utilities shared across the entire codebase.
README.md 和 contributing.md 一般都是英文的。可能会难倒一部分人。其实看不懂,完全可以可以借助划词翻译,整页翻译和谷歌翻译等翻译工具。再把英文加入后续学习计划。
本文就是讲 shared 模块,对应的文件路径是:`vue/vue/src/shared`[5]。
也可以用github1s访问,速度更快。github1s vue/vue/src/shared[6]
源代码的代码`vue/vue/src/shared`[7],使用了Flow[8] 类型,可能不太好理解。
为了降低文章难度,我们直接学习源码仓库中的打包后的 dist/vue.js 14行到379行[9]。
当然,前面可能比较啰嗦。我可以直接讲 3. 工具函数。但通过我上文的介绍,即使是初学者,都能看懂一些开源项目源码,也许就会有一定的成就感。另外,面试问到被类似的问题或者笔试题时,你说看Vue2源码学到的,面试官绝对对你刮目相看。
打包后的 vue.js 14行到379行[10],接下来就是解释其中的这些方法。
冻结对象。第一层无法修改。对象中也有判断是否冻结的方法。
Object.isFrozen(emptyObject); // true关于对象 API 推荐看之前我的文章 JavaScript 对象所有API解析[11]
还可以看阮一峰老师的ES6 入门书籍 reflect[12]
JavaScript中假值有六个。
false null undefined 0 '' (空字符串) NaN为了判断准确,Vue2 源码中封装了isDef、 isTrue、isFalse函数来准确判断。
见名知意。
function isDef (v) { return v !== undefined && v !== null }见名知意。
function isTrue (v) { return v === true }见名知意。
function isFalse (v) { return v === false }判断是否是字符串、或者数字、或者 symbol、或者布尔值。
/** * Check if value is primitive. */ function isPrimitive (value) { return ( typeof value === 'string' || typeof value === 'number' || // $flow-disable-line typeof value === 'symbol' || typeof value === 'boolean' ) }因为 typeof null 是 'object'。数组等用这个函数判断也是 true
/** * Quick object check - this is primarily used to tell * Objects from primitive values when we know the value * is a JSON-compliant type. */ function isObject (obj) { return obj !== null && typeof obj === 'object' } // 例子: isObject([]) // true // 有时不需要严格区分数组和对象Object.prototype.toString() 方法返回一个表示该对象的字符串。
mdn[13]
ecma 规范[14],说明了这些类型。
ecma 规范
ECMAScript5.1 中文版[15]
/** * Get the raw type string of a value, e.g., [object Object]. */ var _toString = Object.prototype.toString; function toRawType (value) { return _toString.call(value).slice(8, -1) } // 例子: toRawType('') // 'String' toRawType() // 'Undefined'数组可用的索引值是 0 ('0')、1 ('1') 、2 ('2') ...
/** * Check if val is a valid array index. */ function isValidArrayIndex (val) { var n = parseFloat(String(val)); return n >= 0 && Math.floor(n) === n && isFinite(val) }该全局 isFinite() 函数用来判断被传入的参数值是否为一个有限数值(finite number)。在必要情况下,参数会首先转为一个数值。
isFinite mdn[16]
isFinite(Infinity); // false isFinite(NaN); // false isFinite(-Infinity); // false isFinite(0); // true isFinite(2e64); // true, 在更强壮的Number.isFinite(null)中将会得到false isFinite('0'); // true, 在更强壮的Number.isFinite('0')中将会得到false这里用 isDef 判断其实相对 isObject 来判断 来说有点不严谨。但是够用。
转换成字符串。是数组或者对象并且对象的 toString 方法是 Object.prototype.toString,用 JSON.stringify 转换。
/** * Convert a value to a string that is actually rendered. */ function toString (val) { return val == null ? '' : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString) ? JSON.stringify(val, null, 2) : String(val) }转换成数字。如果转换失败依旧返回原始字符串。
/** * Convert an input value to a number for persistence. * If the conversion fails, return original string. */ function toNumber (val) { var n = parseFloat(val); return isNaN(n) ? val : n } toNumber('a') // 'a' toNumber('1') // 1 toNumber('1a') // 1 toNumber('a1') // 'a1'传入一个以逗号分隔的字符串,生成一个 map(键值对),并且返回一个函数检测 key 值在不在这个 map 中。第二个参数是小写选项。
/** * Make a map and return a function for checking if a key * is in that map. */ function makeMap ( str, expectsLowerCase ) { var map = Object.create(null); var list = str.split(','); for (var i = 0; i -1) { return arr.splice(index, 1) } } }splice 其实是一个很耗性能的方法。删除数组中的一项,其他元素都要移动位置。
引申:`axios InterceptorManager` 拦截器源码[17] 中,拦截器用数组存储的。但实际移除拦截器时,只是把拦截器置为 null 。而不是用splice移除。最后执行时为 null 的不执行,同样效果。axios 拦截器这个场景下,不得不说为性能做到了很好的考虑。因为拦截器是用户自定义的,理论上可以有无数个,所以做性能考虑是必要的。
看如下 axios 拦截器代码示例:
// 代码有删减 // 声明 this.handlers = []; // 移除 if (this.handlers[id]) { this.handlers[id] = null; } // 执行 if (h !== null) { fn(h); }利用闭包特性,缓存数据
/** * Create a cached version of a pure function. */ function cached (fn) { var cache = Object.create(null); return (function cachedFn (str) { var hit = cache[str]; return hit || (cache[str] = fn(str)) }) }系统学习正则推荐老姚:《JavaScript 正则表达式迷你书》问世了![18],看过的都说好。所以本文不会很详细的描述正则相关知识点。
连字符 - 转驼峰 on-click => onClick
/** * Camelize a hyphen-delimited string. */ var camelizeRE = /-(\w)/g; var camelize = cached(function (str) { return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; }) });首字母转大写
/** * Capitalize a string. */ var capitalize = cached(function (str) { return str.charAt(0).toUpperCase() + str.slice(1) });onClick => on-click
/** * Hyphenate a camelCase string. */ var hyphenateRE = /\B([A-Z])/g; var hyphenate = cached(function (str) { return str.replace(hyphenateRE, '-$1').toLowerCase() });简单来说就是兼容了老版本浏览器不支持原生的 bind 函数。同时兼容写法,对参数的多少做出了判断,使用call和apply实现,据说参数多适合用 apply,少用 call 性能更好。
如果对于call、apply、bind的用法和实现不熟悉,可以查看我在面试官问系列面试官问:能否模拟实现JS的call和apply方法面试官问:能否模拟实现JS的bind方法
把类数组转换成数组,支持从哪个位置开始,默认从 0 开始。
/** * Convert an Array-like object to a real Array. */ function toArray (list, start) { start = start || 0; var i = list.length - start; var ret = new Array(i); while (i--) { ret[i] = list[i + start]; } return ret } // 例子: function fn(){ var arr1 = toArray(arguments); console.log(arr1); // [1, 2, 3, 4, 5] var arr2 = toArray(arguments, 2); console.log(arr2); // [3, 4, 5] } fn(1,2,3,4,5);
桩桩充电官方版下载v2.4.2 安卓版
80.31MB |生活服务
中国天气通专业版最新版下载v9.1.0.4 官方安卓版
56.95MB |系统工具
新疆联通网上营业厅官方版(又名中国联通)下载v12.8 安卓客户端
118.17MB |生活服务
联通手机营业厅关怀版(又名中国联通)下载v12.8 安卓最新版
118.17MB |生活服务
28hse香港租屋网APP下载v3.14.0 手机版
51.07MB |生活服务
唐山联通掌上营业厅(中国联通)下载v12.8 安卓版
118.17MB |生活服务
新货多app下载v2.6.2 安卓最新版
65.91MB |生活服务
东梨短剧免费正版app下载v4.0.3 安卓版
61MB |影音播放
2022-03-26
2022-03-26
2022-03-26
2022-03-26
2022-03-26
2022-03-26
2022-03-26
2022-03-26
2022-02-15
2022-02-14