前言
在Vue2中,也有许多的工具函数,这里记录一些常用的工具函数。本文我们学习Vue2中shared/util.js中的工具函数。本文学习的是打包后的 dist/vue.js 14行到379行
工具函数
emptyObject
- 1/*!<br>2 * Vue.js v2.6.14<br>3 * (c) 2014-2021 Evan You<br>4 * Released under the MIT License.<br>5 */<br>6 var emptyObject = Object.freeze({});<br>
复制代码 freeze冻结一个对象,使其不可修改。这个函数在Vue2中经常用到,比如在Vue2中,data函数返回的对象就是被冻结的,防止用户修改data函数返回的对象。
isUndef是否未定义
- 1 function isUndef (v) {<br>2 return v === undefined || v === null<br>3 }<br>
复制代码 判断一个变量是否未定义或者为null,在JavaScript中,假值有6个
- undefined
- null
- false
- 0
- NaN
- ''
为了判断准确,Vue2 源码中封装了isDef、 isTrue、isFalse函数来准确判断。
isDef是否已经定义
- 1 function isDef (v) {<br>2 return v !== undefined && v !== null<br>3 }<br>
复制代码 isTrue是否为真值
- 1function isTrue (v) {<br>2 return v === true<br>3 }<br>
复制代码 isFalse是否为假
- 1function isFalse (v) {<br>2 return v === false<br>3 }<br>
复制代码 isPrimitive是否基本类型
- 1 function isPrimitive (value) {<br>2 return (<br>3 typeof value === 'string' ||<br>4 typeof value === 'number' ||<br>5 // $flow-disable-line<br>6 typeof value === 'symbol' ||<br>7 typeof value === 'boolean'<br>8 )<br>9 }<br>
复制代码 isObject是否对象
因为 typeof null是 'object'。数组等用这个函数判断也是 true- 1 /**<br>2 * Quick object check - this is primarily used to tell<br>3 * Objects from primitive values when we know the value<br>4 * is a JSON-compliant type.<br>5 */<br>6 function isObject (obj) {<br>7 return obj !== null && typeof obj === 'object'<br>8 }<br>
复制代码 toRawType 转换成原始类型
Object.prototype.toString;返回一个表示该对象的字符串- 1 function toRawType (value) {<br>2 return _toString.call(value).slice(8, -1)<br>3 }<br>
复制代码 isPlainObject是否是纯对象
- 1 function isPlainObject (obj) {<br>2 return _toString.call(obj) === '[object Object]'<br>3 }<br>
复制代码 isRegExp是否是正则表达式
- 1function isRegExp (v) {<br>2 return _toString.call(v) === '[object RegExp]'<br>
复制代码 isValidArrayIndex 是否是可用的数组索引值
数组可用的索引值是 0 ('0')、1 ('1') 、2 ('2') …- 1function isValidArrayIndex (val) {<br>2 var n = parseFloat(String(val));<br>3 return n >= 0 && Math.floor(n) === n && isFinite(val)<br>4 }<br>
复制代码 该全局 isFinite()函数用来判断被传入的参数值是否为一个有限数值(finite number)。在必要情况下,参数会首先转为一个数值。- 1isFinite(Infinity); // false<br>2isFinite(NaN); // false<br>3isFinite(-Infinity); // false<br>4isFinite(0); // true<br>5isFinite(2e64); // true,在更强壮的 Number.isFinite(null) 中将会得到 false<br>6isFinite("0"); // true,在更强壮的 Number.isFinite('0') 中将会得到 false<br>
复制代码 isPromise判断是否是promise对象
- 1 function isPromise (val) {<br>2 return (<br>3 isDef(val) &&<br>4 typeof val.then === 'function' &&<br>5 typeof val.catch === 'function'<br>6 )<br>
复制代码 toString 转换成字符串
转换成字符串。是数组或者对象并且对象的 toString 方法是 Object.prototype.toString,用 JSON.stringify 转换。- 1 /**<br> 2 * Convert a value to a string that is actually rendered.<br> 3 */<br> 4function toString (val) {<br> 5 return val == null<br> 6 ? ''<br> 7 : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)<br> 8 ? JSON.stringify(val, null, 2)<br> 9 : String(val)<br>10}<br>
复制代码 toNumber转数字
转换成数字,如果转换失败,返回原值- 1 function toNumber (val) {<br>2 var n = parseFloat(val);<br>3 return isNaN(n) ? val : n<br>4 }<br>
复制代码 makeMap生成一个map(对象)
传入一个以逗号分隔的字符串,生成一个map键值对,并且返回一个函数检测key值在不在这个map中。第二个参数是小写选项。- 1 function makeMap (<br> 2 str,<br> 3 expectsLowerCase<br> 4 ) {<br> 5 var map = Object.create(null);<br> 6 var list = str.split(',');<br> 7 for (var i = 0; i < list.length; i++) {<br> 8 map[list[i]] = true;<br> 9 }<br>10 return expectsLowerCase<br>11 ? function (val) { return map[val.toLowerCase()]; }<br>12 : function (val) { return map[val]; }<br>13 }<br>
复制代码 注意:通过splice方法移除数组,是个耗性能的操作,因为数组的索引会重新计算。
在axios InterceptorManager源码中,拦截器用数组存储的。但实际移除拦截器时,只是把拦截器置为 null 。而不是用`splice移除。最后执行时为 null 的不执行,同样效果,但性能更好。
- 1/**<br> 2 * Check if a tag is a built-in tag.<br> 3 */<br> 4var isBuiltInTag = makeMap('slot,component', true);<br> 5<br> 6// 返回的函数,第二个参数不区分大小写<br> 7isBuiltInTag('slot') // true<br> 8isBuiltInTag('component') // true<br> 9isBuiltInTag('Slot') // true<br>10isBuiltInTag('Component') // true<br>
复制代码 hasOwn 检测是否是自己的属性
- 1/**<br> 2 * Check if an attribute is a reserved attribute.<br> 3 */<br> 4var isReservedAttribute = makeMap('key,ref,slot,slot-scope,is');<br> 5<br> 6isReservedAttribute('key') // true<br> 7isReservedAttribute('ref') // true<br> 8isReservedAttribute('slot') // true<br> 9isReservedAttribute('slot-scope') // true<br>10isReservedAttribute('is') // true<br>11isReservedAttribute('IS') // undefined<br>
复制代码 cached缓存
利用闭包特性,缓存数据- 1 /**<br> 2 * Remove an item from an array.<br> 3 */<br> 4 function remove (arr, item) {<br> 5 if (arr.length) {<br> 6 var index = arr.indexOf(item);<br> 7 if (index > -1) {<br> 8 return arr.splice(index, 1)<br> 9 }<br>10 }<br>11 }<br>
复制代码 camelizeRE连字符转小驼峰
连字符 - 转驼峰 on-click => onClick- 1'use strict';<br> 2<br> 3var utils = require('./../utils');<br> 4<br> 5function InterceptorManager() {<br> 6 this.handlers = [];<br> 7}<br> 8<br> 9/**<br>10 * Add a new interceptor to the stack<br>11 *<br>12 * @param {Function} fulfilled The function to handle `then` for a `Promise`<br>13 * @param {Function} rejected The function to handle `reject` for a `Promise`<br>14 *<br>15 * @return {Number} An ID used to remove interceptor later<br>16 */<br>17InterceptorManager.prototype.use = function use(fulfilled, rejected, options) {<br>18 this.handlers.push({<br>19 fulfilled: fulfilled,<br>20 rejected: rejected,<br>21 synchronous: options ? options.synchronous : false,<br>22 runWhen: options ? options.runWhen : null<br>23 });<br>24 return this.handlers.length - 1;<br>25};<br>26<br>27/**<br>28 * Remove an interceptor from the stack<br>29 *<br>30 * @param {Number} id The ID that was returned by `use`<br>31 */<br>32InterceptorManager.prototype.eject = function eject(id) {<br>33 if (this.handlers[id]) {<br>34 this.handlers[id] = null;<br>35 }<br>36};<br>37<br>38/**<br>39 * Clear all interceptors from the stack<br>40 */<br>41InterceptorManager.prototype.clear = function clear() {<br>42 if (this.handlers) {<br>43 this.handlers = [];<br>44 }<br>45};<br>46<br>47/**<br>48 * Iterate over all the registered interceptors<br>49 *<br>50 * This method is particularly useful for skipping over any<br>51 * interceptors that may have become `null` calling `eject`.<br>52 *<br>53 * @param {Function} fn The function to call for each interceptor<br>54 */<br>55InterceptorManager.prototype.forEach = function forEach(fn) {<br>56 utils.forEach(this.handlers, function forEachHandler(h) {<br>57 if (h !== null) {<br>58 fn(h);<br>59 }<br>60 });<br>61};<br>62<br>63module.exports = InterceptorManager;<br>
复制代码 capitalize首字母转大写
- 1/**<br> 2 * Check whether an object has the property.<br> 3 */<br> 4var hasOwnProperty = Object.prototype.hasOwnProperty;<br> 5function hasOwn (obj, key) {<br> 6 return hasOwnProperty.call(obj, key)<br> 7}<br> 8<br> 9// 例子:<br>10<br>11// 特别提醒:__proto__ 是浏览器实现的原型写法,后面还会用到<br>12// 现在已经有提供好几个原型相关的API<br>13// Object.getPrototypeOf<br>14// Object.setPrototypeOf<br>15// Object.isPrototypeOf<br>16<br>17// .call 则是函数里 this 显示指定以为第一个参数,并执行函数。<br>18<br>19hasOwn({__proto__: { a: 1 }}, 'a') // false<br>20hasOwn({ a: undefined }, 'a') // true<br>21hasOwn({}, 'a') // false<br>22hasOwn({}, 'hasOwnProperty') // false<br>23hasOwn({}, 'toString') // false<br>24// 是自己的本身拥有的属性,不是通过原型链向上查找的。<br>
复制代码 hyphenateRE小驼峰转连字符
- 1/**<br> 2 * Create a cached version of a pure function.<br> 3 */<br> 4 function cached (fn) {<br> 5 var cache = Object.create(null);<br> 6 return (function cachedFn (str) {<br> 7 var hit = cache[str];<br> 8 return hit || (cache[str] = fn(str))<br> 9 })<br>10 }<br>
复制代码 polyfillBind bind 的垫片
- 1 /**<br>2 * Camelize a hyphen-delimited string.<br>3 */<br>4 var camelizeRE = /-(\w)/g;<br>5 var camelize = cached(function (str) {<br>6 return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; })<br>7 });<br>
复制代码 兼容了老版本浏览器不支持原生的 bind 函数。同时兼容写法,对参数的多少做出了判断,使用call和apply实现,据说参数多适合用 apply,少用 call性能更好。
toArray把类数组转换成真正的数组
把类数组转换成数组,支持从哪个位置开始,默认从 0 开始。- 1 /**<br>2 * Capitalize a string.<br>3 */<br>4 var capitalize = cached(function (str) {<br>5 return str.charAt(0).toUpperCase() + str.slice(1)<br>6 });<br>
复制代码 extend合并
- 1/**<br>2 * Hyphenate a camelCase string.<br>3 */<br>4 var hyphenateRE = /\B([A-Z])/g;<br>5 var hyphenate = cached(function (str) {<br>6 return str.replace(hyphenateRE, '-$1').toLowerCase()<br>7 });<br>
复制代码 toObject 转对象
[code] 1/**
2 * Merge an Array of Objects into a single Object.
3 */
4function toObject (arr) {
5 var res = {};
6 for (var i = 0; i |