Lodash 源码阅读-stringSize
概述
stringSize 是 Lodash 内部的工具函数,用于获取字符串中的字符数量。它能够正确处理包含 Unicode 字符的字符串,确保对于包含表情符号、变音符号或其他特殊 Unicode 字符的字符串也能返回准确的字符数量,而不仅仅是 JavaScript 原生 length 属性返回的代码单元数。
前置学习
依赖函数
- hasUnicode:检测字符串是否包含 Unicode 字符(如表情符号、变音符号等)
- unicodeSize:计算包含 Unicode 字符的字符串中实际字符数量
- asciiSize:计算 ASCII 字符串的长度,实际上是
baseProperty('length')的别名
技术知识
- Unicode 字符编码:理解 UTF-16 编码和代理对(surrogate pairs)
- JavaScript 字符串处理:了解 JavaScript 如何处理 Unicode 字符串
- 正则表达式:了解如何使用正则表达式匹配 Unicode 字符
- 高阶函数:理解返回函数的函数
源码实现
function stringSize(string) {
return hasUnicode(string) ? unicodeSize(string) : asciiSize(string);
}
实现思路
stringSize 函数的实现思路清晰简洁:
- 首先使用
hasUnicode检查输入字符串是否包含 Unicode 字符 - 如果包含 Unicode 字符,调用专门的
unicodeSize函数计算字符数量 - 如果只包含 ASCII 字符,使用性能更好的
asciiSize函数(即直接返回字符串的length属性值)
这种实现采用了条件分发的策略,根据字符串的特性选择最合适的处理方法,既保证了结果的准确性,又优化了性能。
源码解析
1. 核心实现逻辑
stringSize 函数通过三元运算符实现了条件分发的逻辑:
function stringSize(string) {
return hasUnicode(string) ? unicodeSize(string) : asciiSize(string);
}
这种结构使代码非常清晰:检查字符串特性,然后选择合适的处理函数。这也是 Lodash 中常见的性能优化模式:先检查简单情况,再处理复杂情况。
2. 依赖函数分析
stringSize 主要依赖三个函数,每个函数都有特定的职责:
① hasUnicode 函数
这个函数判断字符串是否包含 Unicode 字符。它使用专门设计的正则表达式来检测各种 Unicode 字符,包括零宽连接符、星座平面字符、组合标记和变体选择符等。它的判断结果决定了后续使用哪个函数计算字符串长度。
② unicodeSize 函数
当字符串包含 Unicode 字符时,使用这个函数计算实际字符数量。它通过正则表达式迭代匹配所有 Unicode 字符,确保能正确计算复杂 Unicode 序列(如表情符号)的数量。
③ asciiSize 函数
当字符串只包含 ASCII 字符时,使用这个更高效的函数获取长度。它是 baseProperty('length') 的结果,简单地返回字符串的 length 属性值。
3. 在 size 函数中的应用
stringSize 主要在 Lodash 的 size 函数中使用,用于计算字符串的大小:
function size(collection) {
if (collection == null) {
return 0;
}
if (isArrayLike(collection)) {
return isString(collection) ? stringSize(collection) : collection.length;
}
var tag = getTag(collection);
if (tag == mapTag || tag == setTag) {
return collection.size;
}
return baseKeys(collection).length;
}
当传入 size 函数的是字符串时,会调用 stringSize 来计算字符数量。
4. 示例说明
// ASCII 字符串 - 使用 asciiSize
stringSize("Hello"); // 返回 5
// 包含 Unicode 字符的字符串 - 使用 unicodeSize
stringSize("你好,世界"); // 返回 5
stringSize("👨👩👧👦"); // 返回 1(一个家庭表情,虽然由多个代码点组成)
// 在 lodash.size 中的应用
_.size("Hello"); // 返回 5
_.size("你好,世界"); // 返回 5
_.size("👨👩👧👦"); // 返回 1
总结
stringSize 函数虽然代码简短,但它巧妙地解决了 JavaScript 中处理 Unicode 字符串长度的复杂问题:
-
智能分派策略:通过检测字符串是否包含 Unicode 字符,选择最合适的计算方法
-
性能优化:对于常见的 ASCII 字符串使用快速路径,避免不必要的计算
-
准确性:能够正确计算包含复杂 Unicode 字符(如表情符号)的字符串长度