小曹同学的百草园
首页
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

小曹同学

一个普通的前端开发
首页
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • vue3源码基础工具函数

  • 源码学习笔记
小曹同学
2021-11-28

vue3源码基础工具函数

# vue3源码基础工具函数[^1]

# 1、EMPTY_OBJ空对象

/**
 * - `object.freeze` 冻结对象内置api
 * - 冻结对象的最外层无法修改
 */
const EMPTY_OBJ_1 = Object.freeze({});
EMPTY_OBJ_1.name = '小曹'
console.log(EMPTY_OBJ_1.name)
const EMPTY_OBJ_2 = Object.freeze({ props: { mp: '小曹' } })
EMPTY_OBJ_2.props.name = '小曹2'
EMPTY_OBJ_2.props2 = 'props2'
console.log(EMPTY_OBJ_2.props.name)
console.log(EMPTY_OBJ_2.props2)
console.log(EMPTY_OBJ_2)
1
2
3
4
5
6
7
8
9
10
11
12
13
输出结果

# 2、NOOP空函数

使用场景

  1. 方便判断:初始化instance的render属性时将NOOP赋值于它,render一旦发生了赋值行为不管被赋值的方法字面上是否和NOOP一样最后都不再等于NOOP了。可以用来判断属性初始化后续有无再改变。

  2. 方便压缩

const NOOP = () => { }
const instance = { render: NOOP }
const dev = true;
// if (dev) {
//   instance.render = function () {
//     console.log('hello xiaocao render')
//   }
// }

if (instance.render === NOOP) {
  console.log(true)
}

instance.render()
1
2
3
4
5
6
7
8
9
10
11
12
13
14

render没有改变时

const NOOP = () => { }
const instance = { render: NOOP }
const dev = true;
 if (dev) {
   instance.render = function () {
     console.log('hello xiaocao render')
   }
 }

if (instance.render === NOOP) {
  console.log(true)
}

instance.render()
1
2
3
4
5
6
7
8
9
10
11
12
13
14

render赋值改变后

# 3、isOn判断字符串是否on开头

  • 正则表达式^在开头则表示以什么为开头,否则就是指非。

  • $符号在结尾则表示以什么结尾

  • eg:/^a[^a-z]b$/以a开头的非a~z之间的以b结尾的字符


const onRE = /^on[^a-z]/
const isOn = key => console.log(onRE.test(key))

isOn('onhappy')//false
isOn('onHappy')//true

const ex = /^a[^a-z]b$/
const isEx = key => console.log(ex.test(key))
isEx('aSb')// true
isEx('awb')// false
isEx('aSS')// false
isEx('dSS')// false
1
2
3
4
5
6
7
8
9
10
11
12
13

# 4、remove移除数组中的一项

相关知识:

  • Array.prototype.indexOf(): indexOf()方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。
  • Array.prototype.splice():splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。

注:splice是很耗性能的方法,删除数组中的一项,其他的元素都会移动位置。axios InterceptorManager 拦截器移除拦截器时是将拦截器设置为null。最后执行时为null的不执行。性能更加优化

// 利用splice移除数组项
const remove = (arr, el) => {
  const i = arr.indexOf(el)
  if (i > -1) {
    arr.splice(i, 1)
  }
}

let arr = [1, 2, 3]
remove(arr, 3)
console.log(arr) // [1, 2]


// axios拦截器代码
// 代码有删减
// 声明
this.handlers = [];

// 移除
if (this.handlers[id]) {
    this.handlers[id] = null;
}

// 执行
if (h !== null) {
    fn(h);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 5、判断字符串是否以onUpdate:开头

参考资料:实例方法:includes(), startsWith(), endsWith() (opens new window)

/**
 * - 判断字符串是否以`onUpdate:`开头
 */
const isModeListener = key => key.startsWith('onUpdate:');

console.log(isModeListener('onUpdate:change')) // true
console.log(isModeListener('1onUpdate:change'))// false
console.log(isModeListener('1onUpdatechange'))// false
1
2
3
4
5
6
7
8

# 6、extend 继承 合并

利用Object.assign方法实现继承与合并

  • Object.assign() 方法用于将所有==可枚举属性==的值从一个或多个源对象分配到目标对象。它将==返回目标对象==。

如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。

/**
 * - extend 继承 合并
 */
const extend = Object.assign;

const data = { name: '小曹' }
const data2 = extend(data, { mp: '小曹1', name: '小曹1' })
console.log(data)
console.log(data2)
1
2
3
4
5
6
7
8
9

# 7、hasOwn 判断是否本身所拥有的的属性

  • Object.prototype.hasOwnProperty():hasOwnProperty() 方法会返回一个布尔值,指示对象==自身属性==中是否具有指定的属性(也就是,是否有指定的键)。
/**
 * - hasOwn 判断是否本身所拥有的的属性,不通过原型链向上查找
 */
const hasOwnProperty = Object.prototype.hasOwnProperty;
const hasOwn = (val, key) => hasOwnProperty.call(val, key)
console.log(hasOwn({__proto__: {a: 1}}, 'a'))// false
console.log(hasOwn({a: undefined}, 'a'))// true
console.log(hasOwn({}, 'toString'))// false
console.log(hasOwn({}, 'a'))// false
1
2
3
4
5
6
7
8
9

# 8、isArray判断数组

const isArray = Array.isArray
console.log(isArray([]))

//严谨改良版
function isArray (arr) {
  return Object.prototype.toString.call(arr) === '[object Array]' &&
    Array.isArray(arr) &&
    arr.__proto__ === Array.prototype &&
    arr instanceof Array
}

1
2
3
4
5
6
7
8
9
10
11

# 9、isMap判断是否为map

/**
 * - isMap判断是否为Map对象
 */

const isMap = val => val.toString() === '[object Map]'

const map = new Map()
const o = { p: 'hello word' }
map.set(o, 'content')
console.log(map)
console.log(isMap({}))// false
console.log(isMap(map))// true
1
2
3
4
5
6
7
8
9
10
11
12

# 10、isSet判断是否set对象

const isSet = (val) => toTypeString(val) === '[object Set]';

const set = new Set();
console.log(isSet(set)) // true
1
2
3
4

# 11、isDate判断是否Date对象

instanceof操作符左边是右边的实例;

  • 原理是根据原型链向上查找,如果能找到则返回true;所以并不是非常准确
const isDate = val => console.log(val instanceof Date)

isDate(new Date)// true
isDate({ __proto__: new Date() })// true 严格来说应该是false 
1
2
3
4

# 12、isFunction判断是不是函数

const isFunction = val => typeof val === 'function'
console.log(isFunction(()=>{}))// true
console.log(isFunction({}))// false
console.log(isFunction(new Function))// true
1
2
3
4

# 13、由toTypeString 对象转字符串等引申的升级版typeof

💡Object.prototype.toString.call(obj):通过call改变获取toString方法获取类型'[object String]'来进行简单的类型判断

/**
 * -typeof进阶版
 * @param {*} obj 需要进行检查的参数
 * @param {boolean} fullClass 是否仅仅是简单进行类型判断
 * @returns {string} 类型字符串
 */
function type (obj, fullClass) {
  if (fullClass) {
    return (obj === null) ? '[object Null]' : Object.prototype.toString.call(obj)
  }
  // 判断参数为Null直接返回字符串’null‘
  if (obj === null) {
    return (obj + '').toLowerCase()
  }
  var deepType = Object.prototype.toString.call(obj).slice(8, -1).toLowerCase()
  if (deepType === 'generatorfunction') {
    return 'function'
  }

  // 检查一下防止边缘情况的发生导致判断不准确,比如[object, HTMLDivElement]..
  return deepType.match(/^(array|bigint|date|error|function|generator|regexp|symbol)$/) ?
    deepType : (typeof obj === 'object' || typeof obj === 'function') ? 'object' : typeof obj;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

[^1]:初学者也能看懂的 Vue3 源码中那些实用的基础工具函数 (opens new window) ↩

编辑 (opens new window)
上次更新: 2022/02/21, 05:57:00
最近更新
01
优雅代码书写之道
06-07
02
图片懒加载
05-05
03
项目部署
04-16
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式