36个Vue2源码中的实用工具函数分析
2023-10-18 19:00:29
Vue 2 中的实用工具函数:深入理解和应用
简介
Vue 2 的核心是一个健壮且功能丰富的 JavaScript 框架,它提供了许多开箱即用的工具函数,用于简化和增强其功能。这些工具函数位于共享模块中,提供了广泛的功能,从对象操作到函数绑定,不一而足。本文将逐一深入探讨这些工具函数,揭示其功能、应用场景以及对 Vue 2 开发的价值。
对象操作
isObject
export function isObject(obj: unknown): obj is object {
return obj !== null && typeof obj === 'object'
}
isObject 函数确定一个变量是否为对象。在 JavaScript 中,对象是引用类型,存储在堆内存中并通过引用访问。isObject 通过检查变量的类型是否为 'object' 且不为 null 来确定它是否为对象。
isPlainObject
export function isPlainObject(obj: unknown): obj is object {
return isObject(obj) && Object.prototype.toString.call(obj) === '[object Object]'
}
isPlainObject 函数用于判断一个变量是否为普通对象。普通对象是指由 Object 构造函数创建的对象,不包含原型链。isPlainObject 首先检查变量是否为对象,然后检查它的原型链是否为 Object.prototype,如果是,则它是一个普通对象。
def
export function def(obj: object, key: string | symbol, value: any, enumerable?: boolean) {
Object.defineProperty(obj, key, {
value,
enumerable: !!enumerable,
writable: true,
configurable: true
})
}
def 函数在对象上定义一个属性。它接受四个参数:对象、属性名、属性值和是否可枚举。def 函数使用 Object.defineProperty() 方法来定义属性,并设置属性的可枚举性、可写性和可配置性。
hasOwn
export function hasOwn(obj: object, key: string | symbol): boolean {
return Object.prototype.hasOwnProperty.call(obj, key)
}
hasOwn 函数用于判断一个对象是否拥有某个属性。它接受两个参数:对象和属性名。hasOwn 函数使用 Object.prototype.hasOwnProperty() 方法来判断对象是否拥有该属性。
函数操作
cached
export function cached<F extends Function>(fn: F): F {
const cache: Record<string, any> = Object.create(null)
return function cachedFn(str: string) {
const hit = cache[str]
return hit || (cache[str] = fn(str))
}
}
cached 函数对函数进行缓存。它接受一个函数作为参数,并返回一个缓存后的函数。缓存后的函数会将函数的调用结果缓存起来,当再次调用时,直接从缓存中获取结果,从而提高性能。
bind
export function bind(fn: Function, ctx: object): Function {
return function boundFn(a: any, b: any, c: any) {
return fn.call(ctx, a, b, c)
}
}
bind 函数将一个函数绑定到一个上下文。它接受两个参数:函数和上下文对象。bind 函数返回一个新的函数,该函数在被调用时,会将上下文对象作为 this 指向。
数据转换
toArray
export function toArray<T>(list: T[] | NodeList): T[] {
let i = list.length
const ret: T[] = new Array(i)
while (i--) {
ret[i] = list[i]
}
return ret
}
toArray 函数将一个类数组对象转换为数组。它接受一个类数组对象作为参数,并返回一个数组。toArray 函数通过遍历类数组对象,将每个元素添加到数组中来实现。
extend
export function extend<T, U>(to: T, from: U): T & U {
for (const key in from) {
to[key] = from[key]
}
return to as T & U
}
extend 函数将一个对象的属性复制到另一个对象。它接受两个参数:目标对象和源对象。extend 函数通过遍历源对象,将每个属性复制到目标对象中来实现。
toObject
export function toObject<T>(arr: T[]): Record<string | number, T> {
const res: Record<string | number, T> = {}
for (let i = 0; i < arr.length; i++) {
res[i] = arr[i]
}
return res
}
toObject 函数将一个数组转换为对象。它接受一个数组作为参数,并返回一个对象。toObject 函数通过遍历数组,将每个元素添加到对象中来实现。
其他工具
noop
export function noop(a?: any, b?: any, c?: any) {}
noop 函数是一个空函数。它接受任意数量的参数,但不会做任何事情。noop 函数通常用于占位或作为默认值。
identity
export function identity<T>(x: T): T {
return x
}
identity 函数是一个恒等函数。它接受任何类型的值作为参数,并返回该值本身。identity 函数通常用于作为默认值或占位。
looseEqual
export function looseEqual(a: any, b: any): boolean {
if (a === b) return true
const isObjectA = isObject(a)
const isObjectB = isObject(b)
if (isObjectA && isObjectB) {
try {
const isArrayA = Array.isArray(a)
const isArrayB = Array.isArray(b)
if (isArrayA && isArrayB) {
return looseEqualArray(a, b)
} else if (!isArrayA && !isArrayB) {
const keysA = Object.keys(a)
const keysB = Object.keys(b)
return keysA.length === keysB.length && keysA.every(key => looseEqual(a[key], b[key]))
} else {
return false
}
} catch (e) {
return false
}
} else if (!isObjectA && !isObjectB) {
return String(a) === String(b)
} else {
return false
}
}
looseEqual 函数用于比较两个值是否松散相等。它接受两个参数:两个值。looseEqual 函数首先比较两个值是否严格相等。如果严格相等,则返回 true。否则,比较两个值是否都是对象。如果都是对象,则比较它们的属性是否松散相等。如果属性松散相等,则返回 true。否则,比较两个值是否都是数组。如果都是数组,则比较它们的元素是否松散相等。如果元素松散相等,则返回 true。否则,比较两个值是否都是字符串。如果都是字符串,则比较它们的字符串值是否相等。如果相等,则返回 true。否则,返回 false。
looseIndexOf
export function looseIndexOf(arr: any[], val: any): number {
for (let i = 0; i < arr.length; i++) {
if (looseEqual(arr[i], val)) {】