返回

36个Vue2源码中的实用工具函数分析

前端

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)) {】