找回密码
 立即注册
首页 业界区 安全 Vue2源码中实用的工具函数

Vue2源码中实用的工具函数

县挫伪 2025-5-30 13:32:28
前言

在Vue2中,也有许多的工具函数,这里记录一些常用的工具函数。本文我们学习Vue2中shared/util.js中的工具函数。本文学习的是打包后的 dist/vue.js 14行到379行
工具函数

emptyObject
  1. 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. 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. 1  function isDef (v) {<br>2    return v !== undefined && v !== null<br>3  }<br>
复制代码
isTrue是否为真值
  1. 1function isTrue (v) {<br>2    return v === true<br>3  }<br>
复制代码
isFalse是否为假
  1. 1function isFalse (v) {<br>2    return v === false<br>3  }<br>
复制代码
isPrimitive是否基本类型
  1. 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. 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. 1  function toRawType (value) {<br>2    return _toString.call(value).slice(8, -1)<br>3  }<br>
复制代码
isPlainObject是否是纯对象
  1. 1    function isPlainObject (obj) {<br>2    return _toString.call(obj) === '[object Object]'<br>3  }<br>
复制代码
isRegExp是否是正则表达式
  1. 1function isRegExp (v) {<br>2    return _toString.call(v) === '[object RegExp]'<br>
复制代码
isValidArrayIndex 是否是可用的数组索引值

数组可用的索引值是 0 ('0')、1 ('1') 、2 ('2') …
  1. 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)。在必要情况下,参数会首先转为一个数值。
  1. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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 
您需要登录后才可以回帖 登录 | 立即注册