lodash 字符串处理方法capitalize

capitalize函数是一个字符串转换函数,用于把字符串的第一个字母处理为大写字母,剩下的字母处理为小写字母。本文涉及到类型校验(Object.prototype.toString, isSymbol),类型转换(toString),稀疏数组和密集型数组,包含表情的字符串处理。

类型校验

getTag

const toString = Object.prototype.toString
function getTag(value) {
  if (value == null) {
    // 兼容javascript低版本,特殊处理null和undefined
    return value === undefined ? '[object Undefined]' : '[object Null]'
  }
  return toString.call(value)
}
复制代码

isSymbol

调用了getTag方法

function isSymbol(value) {
  const type = typeof value
  return type == 'symbol' || (type === 'object' && value != null && getTag(value) == '[object Symbol]')
}
复制代码

类型转换

toString

将传入的value转换为字符串。数组递归处理(可能会堆栈溢出)。特殊处理-0的情况。引入上面的isSymbol函数

import isSymbol from './isSymbol.js'
/** Used as references for various `Number` constants. */
const INFINITY = 1 / 0

/**
 * Converts `value` to a string. An empty string is returned for `null`
 * and `undefined` values. The sign of `-0` is preserved.
 * value转换为string类型。回null或undefined会返空字符串。-0会被保留
 *
 * @since 4.0.0
 * @category Lang
 * @param {*} value The value to convert.
 * @returns {string} Returns the converted string.
 * @example
 *
 * toString(null)
 * // => ''
 *
 * toString(-0)
 * // => '-0'
 *
 * toString([1, 2, 3])
 * // => '1,2,3'
 */
function toString(value) {
  if (value == null) {
    return ''
  }
  // Exit early for strings to avoid a performance hit in some environments.
  // string类型直接返回
  if (typeof value === 'string') {
    return value
  }
  // 数组类型
  if (Array.isArray(value)) {
    // Recursively convert values (susceptible to call stack limits).
    // 数组项不为null或undefined的情况下,递归调用自身进行转换
    return `${value.map((other) => other == null ? other : toString(other))}`
  }
  // symbol类型调用symbol的toString方法
  if (isSymbol(value)) {
    return value.toString()
  }
  // 处理-0的情况
  const result = `${value}`
  return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result
}
复制代码

处理字符串的第一个字母

createCaseFirst

该函数依赖于castSlice函数,hasUnicode函数以及stringToArray函数。

castSlice函数,相比较于Array.prototype.slice方法,该函数调用自己实现的slice函数并生成一个密集型数组。源码地址。关于密集型数组和稀疏数组:

console.log(new Array(5), new Array(5).fill(undefined))
// [ <5 empty items> ] 稀疏数组
// [ undefined, undefined, undefined, undefined, undefined ] 密集数组
复制代码

hasUnicode函数用于校验传入的字符串是否包含Unicode码表上对应的字符(这里主要是校验是否存在特殊的unicode字符。源码地址。如果存在,就交给stringToArray函数处理,以正确的解析对应的unicode字符),校验范围如下:

// 星芒层
const rsAstralRange = '\\ud800-\\udfff'
// https://www.unicode.org/charts/PDF/U0300.pdf
const rsComboMarksRange = '\\u0300-\\u036f'
// https://www.unicode.org/charts/PDF/UFE20.pdf
const reComboHalfMarksRange = '\\ufe20-\\ufe2f'
// https://www.unicode.org/charts/PDF/U20D0.pdf
const rsComboSymbolsRange = '\\u20d0-\\u20ff'
// https://www.unicode.org/charts/PDF/U1AB0.pdf
const rsComboMarksExtendedRange = '\\u1ab0-\\u1aff'
// https://www.unicode.org/charts/PDF/U1DC0.pdf
const rsComboMarksSupplementRange = '\\u1dc0-\\u1dff'
const rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange + rsComboMarksExtendedRange + rsComboMarksSupplementRange
// fe0e fe0f https://www.unicode.org/charts/PDF/UFE00.pdf
const rsVarRange = '\\ufe0e\\ufe0f'

/** Used to compose unicode capture groups. */
// ZWJ https://www.unicode.org/charts/PDF/U2000.pdf   ZERO WIDTH JOINER
const rsZWJ = '\\u200d'

/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
const reHasUnicode = RegExp(`[${rsZWJ + rsAstralRange + rsComboRange + rsVarRange}]`)
复制代码

stringToArray函数,正如上文中提到的,为了正确解析包含特殊unicode编码的字符串,比如包含表情的字符串。源码地址

createCaseFirst利用传入的methodName对字符串的第一个字母进行处理。如toUpperCase,toLowerCase等存在于String.prototype原型链上的方法

import castSlice from './castSlice.js'
import hasUnicode from './hasUnicode.js'
import stringToArray from './stringToArray.js'

/**
 * Creates a function like `lowerFirst`.
 * 根据传入的methodname 生成对应的函数
 *
 * @private
 * @param {string} methodName The name of the `String` case method to use.
 * @returns {Function} Returns the new case function.
 */
function createCaseFirst(methodName) {
  return (string) => {
    // string 为空字符串 不做任何操作
    if (!string) {
      return ''
    }

    // 包含unicode码,调用内部的asciiToArray和unicodeToArray方法
    const strSymbols = hasUnicode(string)
      ? stringToArray(string)
      : undefined

    // string 字符不包含unicode 默认取string的第一个字符。否则转化为数组后,取第一个字符
    const chr = strSymbols
      ? strSymbols[0]
      : string[0]

    // string截取剩下的字符串。包含unicode情况,截取数组的1到最后一项并转换为字符串
    const trailing = strSymbols
      ? castSlice(strSymbols, 1).join('')
      : string.slice(1)

    // 调用第一个字符串对应的方法执行 prototype上对应的函数 并 追加后续字符串
    // 只对字符串的第一个字符进行操作
    return chr[methodName]() + trailing
  }
}
复制代码

upperFirst

调用createCaseFirst函数,传入toUpperCase作为参数

/**
 * Converts the first character of `string` to upper case.
 * 字符串的第一个字母转换成大写字母
 * 
 * @since 4.0.0
 * @category String
 * @param {string} [string=''] The string to convert.
 * @returns {string} Returns the converted string.
 * @see camelCase, kebabCase, lowerCase, snakeCase, startCase, upperCase
 * @example
 *
 * upperFirst('fred')
 * // => 'Fred'
 *
 * upperFirst('FRED')
 * // => 'FRED'
 */
const upperFirst = createCaseFirst('toUpperCase')
复制代码

capitalize

调用toString函数和upperFirst。先对传入的值调用toString函数,然后调用String.prototype.toLowerCase方法,最后调用upperFirst实现功能

const capitalize = (string) => upperFirst(toString(string).toLowerCase())
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享