本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
-
没使用过vue2的也可以学习,有很多基础知识可以复习巩固。
-
在线vscode 查看 github1s.com/vuejs/vue/b…
-
打包后的工具函数 github.com/vuejs/vue/b…
1.代码目录 src/shared/util.js
2.工具函数
主要分4大类:基本类型检测,引用类型的判断,类型转换,工具函数
2.1 基本类型检测
// These helpers produce better VM code in JS engines due to their
// explicitness and function inlining.
export function isUndef (v: any){
return v === undefined || v === null
}
export function isDef (v: any){
return v !== undefined && v !== null
}
export function isTrue (v: any){
return v === true
}
export function isFalse (v: any){
return v === false
}
//检测是否式基本类型
/**
* Check if value is primitive.
*/
export function isPrimitive (value){
return (
typeof value === 'string' ||
typeof value === 'number' ||
// $flow-disable-line
typeof value === 'symbol' ||
typeof value === 'boolean'
)
}
2.2 引用类型的判断
2.2.1 引用类型判断
export function isObject (obj){
return obj !== null && typeof obj === 'object'
}
/**
* Get the raw type string of a value, e.g., [object Object].
*/
//使用Object.prototype.toString的方法判断类型
const _toString = Object.prototype.toString
export function toRawType (value){
return _toString.call(value).slice(8, -1)
}
//toRawType([])
//'Array'
//toRawType({})
//'Object'
/**
* Strict object type check. Only returns true
* for plain JavaScript objects.
*/
export function isPlainObject (obj){
return _toString.call(obj) === '[object Object]'
}
//判断正则类型
export function isRegExp (v){
return _toString.call(v) === '[object RegExp]'
}
2.2.2 其他类型的判断
/**
* Check if val is a valid array index.
*/
//判断是否式数组的下标
export function isValidArrayIndex (val: any): boolean {
const n = parseFloat(String(val))
return n >= 0 && Math.floor(n) === n && isFinite(val)
}
//promise的类型判断,判断是否有then方法和catch方法
export function isPromise (val: any): boolean {
return (
isDef(val) &&
typeof val.then === 'function' &&
typeof val.catch === 'function'
)
}
扩展:isFinite sFinite() 函数用于检查其参数是否是无穷大,也可以理解为是否为一个有限数值(finite number)。 提示: 如果参数是 NaN,正无穷大或者负无穷大,会返回 false,其他返回 true。
2.3 类型转换
//转换成字符串,如果是引用类型使用JSON.stringify转换
//_toString = Object.prototype.toString
export 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.
*/
export function toNumber (val){
const n = parseFloat(val)
return isNaN(n) ? val : n
}
2.4 工具函数
/**
* Make a map and return a function for checking if a key
* is in that map.
*/
//makeMap方法使用闭包,保存一个map,下次可以调用检查key是否在map中
export function makeMap (str,expectsLowerCase){
const map = Object.create(null)
const list: Array<string> = str.split(',')
for (let i = 0; i < list.length; i++) {
map[list[i]] = true
}
return expectsLowerCase
? val => map[val.toLowerCase()]
: val => map[val]
}
/**
* Check if a tag is a built-in tag.
*/
export const isBuiltInTag = makeMap('slot,component', true)
//isBuiltInTag(component) true
//isBuiltInTag('z') undefined
/**
* Check if an attribute is a reserved attribute.
*/
export const isReservedAttribute = makeMap('key,ref,slot,slot-scope,is')
2.4.2 删除数组中的元素
/**
* Remove an item from an array.
*/
export function remove (arr){
if (arr.length) {
const index = arr.indexOf(item)
if (index > -1) {
return arr.splice(index, 1)
}
}
}
2.4.3 判断是否是对象的本身属性,排除原型上的属性
/**
* Check whether an object has the property.
*/
const hasOwnProperty = Object.prototype.hasOwnProperty
export function hasOwn (obj, key){
return hasOwnProperty.call(obj, key)
}
2.4.4 cache缓存,利用闭包缓存数据
/**
* Create a cached version of a pure function.
*/
export function cached(fn){
const cache = Object.create(null)
return (function cachedFn (str) {
const hit = cache[str]
//若存在hit则返回hit,没有则缓存
return hit || (cache[str] = fn(str))
})
}
2.4.5 bind的兼容写法
/* istanbul ignore next */
function polyfillBind (fn, ctx){
function boundFn (a) {
const l = arguments.length
//根据参数的长度来使用apply或者call
return l
? l > 1
? fn.apply(ctx, arguments)
: fn.call(ctx, a)
: fn.call(ctx)
}
boundFn._length = fn.length
return boundFn
}
function nativeBind (fn, ctx){
return fn.bind(ctx)
}
//函数原型上有bind方法则使用原有的bind,否则使用polyfillBind
export const bind = Function.prototype.bind
? nativeBind
: polyfillBind
2.4.6 once函数
/**
* Ensure a function is called only once.
*/
export function once (fn: Function): Function {
let called = false
return function () {
//利用闭包的特性,保存一个标识,当called=true时表示已经调用过回调函数
if (!called) {
called = true
fn.apply(this, arguments)
}
}
}
小结
- 熟悉了vue中的类型检查和类型转换,
- 熟悉了闭包的特性
- 了解了一些之前不知道的方法,如isFinite