Skip to content

String

[TOC]

索引

属性

  • string.lengthnumber只读,用于获取字符串中 UTF-16 编码单元的数量(非实际字符数)。
  • string.constructorString指向创建该字符串对象的构造函数String

方法

构造函数

  • new String() / String()(value),用于将任意值转换为字符串类型。它既可作为转换函数使用,也可作为构造函数创建字符串对象。

字符访问

  • string.charAt()(index),用于获取指定索引位置的字符
  • string.charCodeAt()(index?),用于获取指定索引位置字符的 UTF-16 编码值
  • string.at()(index?)ES2022,用于获取指定索引位置的字符,支持正负索引访问。

字符串查找

  • string.indexOf()(searchString,position?),区分大小写,用于查找子字符串首次出现的索引位置。从左向右进行,返回基于 0 的索引值。
  • string.lastIndexOf()(searchString,position?),区分大小写,用于查找子字符串最后一次出现的索引位置。搜索从字符串末尾向开头进行(从右向左),返回基于 0 的索引值。
  • string.includes()(searchString, position?)ES2015,区分大小写,用于判断一个字符串是否包含在另一个字符串中
  • string.startsWith()(searchString, position?)ES2015,区分大小写,用于判断字符串是否以指定的子字符串开头
  • string.endsWith()(searchString, length?)ES2015,区分大小写,用于判断字符串是否以指定的子字符串结尾

字符串截取

  • string.slice()(startIndex, endIndex?),用于提取字符串的指定部分并返回新字符串。支持负索引,不自动交换参数,返回新字符串。
  • string.substring()(startIndex, endIndex?),用于提取两个指定索引之间的字符并返回新字符串。不支持负索引,自动参数交换,返回新字符串。
  • string.substr()(startIndex, length?)已废弃,用于从指定位置开始提取指定长度的子字符串。支持负索引,返回新字符串。

字符串修改

  • string.toUpperCase()(),用于将字符串中所有字符转换为大写形式。返回新字符串,支持 Unicode 和多语言字符转换。
  • string.toLowerCase()(),用于将字符串中所有字符转换为小写形式。返回新字符串,支持 Unicode 和多语言字符转换。
  • string.concat()(str1, str2, ..., strN),用于将多个字符串连接成一个新字符串。返回新字符串,功能与 + 操作符相似,支持链式调用。
  • string.repeat()(count)ES2015,用于将字符串重复指定次数后返回新字符串。返回新字符串。
  • string.trim()()ES2015,用于移除字符串两端的空白字符(包括空格、制表符\t\v、换行符\n等)。返回新字符串。
  • string.trimStart()()ES2019,用于移除字符串开头的空白字符(包括空格、制表符、换行符等)。返回新字符串,别名 trimLeft()
  • string.trimEnd()()ES2019,用于移除字符串结尾的空白字符(包括空格、制表符、换行符等)。返回新字符串,别名 trimRight()
  • string.padStart()(targetLength, padString?)ES2017,用于在字符串开头填充指定字符直到字符串达到目标长度。返回新字符串。
  • string.padEnd()(targetLength, padString?)ES2017,用于在字符串结尾填充指定字符直到字符串达到目标长度。返回新字符串。

正则表达式相关

  • string.match()(regexp)支持正则,用于检索字符串中与正则表达式匹配的结果
  • string.matchAll()(regexp)ES2020支持正则必须包含g,用于返回包含所有匹配正则表达式的结果及分组捕获组的迭代器
  • string.search()(regexp)支持正则,用于检索字符串中匹配正则表达式的第一个位置。与 indexOf() 类似但支持正则表达式。
  • string.replace()(searchValue, replaceValue)支持正则,用于替换字符串中匹配的子串。返回新字符串,支持字符串替换和正则表达式替换,并允许使用函数进行高级处理。
  • string.replaceAll()(searchValue, replaceValue)ES2021支持正则,用于全局替换字符串中所有匹配的子串。无需正则表达式即可实现全量替换。
  • string.split()(separator?, limit?)支持正则,用于将字符串分割为子字符串数组。支持限制返回数组长度。

其他

  • string.localeCompare()(compareString,locales?,options?),用于根据当前语言环境比较两个字符串的排序顺序。提供本地化的字符串排序能力,支持多语言排序规则(如德语、中文等)。
  • string.normalize()(form?)ES2015,用于将字符串转换为 Unicode 标准化形式。它解决字符的多种表示方式问题(如组合字符 vs 预组合字符)。

基础

公共参数

searchString

searchStringstring,要查找的子字符串:

  • 字符串:正常搜索。

    js
    "abc".indexOf("b") // 1
    "abcba".lastIndexOf("b") // 3
    "abc".includes("b") // true
    "abc".startsWith("ab") // true
    "abc".endsWith("bc") // true
  • 空字符串:始终返回有效索引或true

    js
    "Hi".indexOf("") // 0
    "Hi".lastIndexOf("") // 2
    "Hi".includes("") // true
    "Hi".startsWith("") // true
    "Hi".endsWith("") // true
  • 非字符串:强制转换为字符串。

    js
    "123".indexOf(2) // 1
    "2023".lastIndexOf(23) // 2
    "123".includes(2) // true
    "123".startsWith(12) // true
    "123".endsWith(23) // true
  • 未提供:相当于搜索 "undefined"。

    js
    "test".indexOf() // -1(搜索"u"失败)
    "test".lastIndexOf() // -1
    "test".includes() // false
    "test".startsWith() // false
    "test".endsWith() // false

position

position?number默认:0,开始搜索的起始位置。

  • 正整数:从指定索引开始搜索。

    js
    "abcabc".indexOf("a", 1) // 3
    "abcabc".lastIndexOf("a", 3) // 3
    "abcabc".includes("a", 1) // true
    "abcabc".startsWith("ca", 2) // true
    "abcabc".endsWith("ab", 3) // false
  • 0:从头开始搜索。

    js
    "abc".indexOf("a", 0) // 0
    "abc".lastIndexOf("a", 0) // 0
    "abc".includes("a", 0) // true
    "abc".startsWith("a", 0) // true
    "abc".endsWith("", 0) // true
  • 负数视为 0

    js
    "abc".indexOf("a", -5) // 0
    "abc".lastIndexOf("c", -5) // -1
    "abc".includes("a", -5) // true
    "abc".startsWith("a", -5) // true
    "abc".endsWith("a", -5) // false
  • 浮点数:取整(非四舍五入)。

    js
    "abc".indexOf("b", 1.9) // 1
    "abc".lastIndexOf("b", 2.9) // 1
    "abc".includes("b", 1.9) // true
    "abc".startsWith("b", 1.9) // true
    "abc".endsWith("c", 2.9) // false
  • 超出长度:直接返回 -1。

    js
    "abc".indexOf("a", 10) // -1
    "abc".lastIndexOf("a", 10) // 0
    "abc".includes("a", 10) // false
    "abc".startsWith("a", 10) // false
    "abc".endsWith("c", 10) // true

搜索方法对比

方法区分大小写搜索方向返回值空串处理典型用例性能
indexOf()正向首次索引/-1返回位置需要位置信息O(n)
lastIndexOf()反向最后索引/-1返回位置需要位置信息O(n)
includes()正向布尔值始终true存在性检查O(n)
search()正向索引/-1(支持正则)返回0正则搜索可变
match()正向匹配数组返回匹配正则匹配【】
startsWith()正向布尔值始终true检查开头O(1)*
endsWith()正向布尔值始终true检查结尾O(1)*

注意startsWith()/endsWith() 在指定位置时性能可能优于 includes()

String

属性

length

string.lengthnumber只读,用于获取字符串中 UTF-16 编码单元的数量(非实际字符数)。

  • 返回:

  • countnumber,非负整数(0 或正整数)。

语法特性

  1. 编码单元计数:按 UTF-16 编码计数(代理对占 2 个长度)。

    js
    "Hello".length;       // 5
    "中文".length;        // 2
    "🚀".length;          // 2(火箭表情为代理对)
  2. 不同字符类型的长度计算

    字符类型示例实际字符数.length说明
    ASCII 字符"A"11单编码单元
    基本多文种平面"中文"22单编码单元/字符
    代理对(表情)"🚀"12双编码单元
    组合字符"é"12基础字符 + 重音组合标记
    零宽连接符"👨‍👩‍👧"1(家庭)8多编码单元组合
  3. 空字符串"" 的长度为 0。

  4. 自动装箱:原始字符串访问时创建临时String对象。

  5. Unicode 敏感:特殊字符可能返回大于 1 的长度。

常见问题

  1. 代理对字符计数错误

    js
    "🚀".length; // 2(但实际是 1 个字符)

    解决方案

    js
    // 方法 1:使用展开运算符
    [..."🚀"].length; // 1
    
    // 方法 2:使用 Intl.Segmenter (ES2022)
    new Intl.Segmenter().segment("🚀").length; // 1
  2. 组合字符被拆分

    js
    "café".length; // 4(但 é 是 e + ́ 组合)

    解决方案:标准化后计算长度。

    js
    "café".normalize().length; // 4(标准化后仍为 4)
    // 正确统计需要字形簇计数
  3. 不可见字符影响长度

    js
    "Hi\u200b".length; // 3(含零宽空格)

    解决方案:替换不可见字符为""

    js
    "Hi\u200b".replace(/\u200b/g, "").length; // 2

示例

  1. 验证输入非空

    js
    function validateInput(text) {
      return text.length > 0;
    }
    validateInput(""); // false
  2. 循环遍历字符

    js
    const str = "A🚀";
    for (let i = 0; i < str.length; i++) {
      console.log(str[i]); 
    }
    // 输出: "A", "\uD83D", "\uDE80"(拆分了代理对)
  3. 获取最后一个字符

    js
    function lastChar(str) {
      return str.charAt(str.length - 1);
    }
    lastChar("React"); // "t"
  4. 截断长文本

    js
    function truncate(text, maxLength) {
      return text.length > maxLength 
        ? text.slice(0, maxLength) + "..." 
        : text;
    }
    truncate("Long text here", 8); // "Long tex..."

constructor

string.constructorString指向创建该字符串对象的构造函数String

  • 返回:

  • strString,创建该字符串的构造函数引用(默认为 String 函数)。

语法

js
// 字符串原始值(自动装箱)
"text".constructor === String; // true

// 显式创建的字符串对象
const strObj = new String("text");
strObj.constructor === String; // true

核心特性

  1. 原型继承:继承自 Object.prototype.constructor

  2. 可修改 constructor:可被重新赋值(强烈不建议)。

    js
    // 自定义字符串类型
    function MyString(value) {
      this.value = value;
    }
    
    // 继承 String 原型的方法
    MyString.prototype = Object.create(String.prototype);
    
    // 重写 constructor 指向
    MyString.prototype.constructor = MyString;
    
    const myStr = new MyString("Custom");
    console.log(myStr.constructor.name); // "MyString"
    console.log(myStr.toUpperCase());    // "CUSTOM"(继承方法)
  3. 类型安全检测:用于判断对象是否为字符串类型。

    js
    function isString(value) {
      return value?.constructor === String;
    }
    
    isString("hello");    // true
    isString(new String("")); // true
    isString(123);        // false
  4. 原始值自动装箱:访问原始字符串的 .constructor 会创建临时对象。

    js
    // 临时对象创建演示
    let count = 0;
    const proxy = new Proxy(String, {
      construct() {
        count++;
        return Reflect.construct(...arguments);
      }
    });
    String = proxy;
    
    "test".constructor; // 触发装箱,count 变为 1

优化处理

  1. 安全替代方案:优先使用类型安全的检测方式。

    • 优先使用 typeof 检测原始字符串。
    • 使用 instanceof 检测字符串对象。
    js
    // 更可靠的字符串检测
    function isSafeString(value) {
      return typeof value === 'string' || 
             (value instanceof String);
    }

示例

  1. 构造函数访问

    js
    const str = "prototype";
    const constructor = str.constructor; // String
    
    // 通过构造函数创建新实例
    const newStr = new constructor("New string");
    console.log(newStr); // String {"New string"}
  2. 跨上下文类型检查

    js
    // iframe 中的字符串
    const iframe = document.createElement('iframe');
    document.body.appendChild(iframe);
    const iframeStr = iframe.contentWindow.String;
    
    // 检测跨上下文字符串
    const crossStr = new iframeStr("test");
    console.log(crossStr.constructor === String);          // false
    console.log(crossStr.constructor.name === "String");   // true

方法

构造函数

new String()

new String() / String()(value),用于将任意值转换为字符串类型。它既可作为转换函数使用,也可作为构造函数创建字符串对象。

  • valueany,接受任何 JS数据类型作为参数。

  • 返回:

  • strstring|String

    • string:作为函数调用时,返回原始字符串值,不可变。
    • String:作为构造函数时,返回 String 对象,包含特殊属性和方法。

语法

js
// 作为转换函数(推荐)
String(value)

// 作为构造函数(不推荐)
new String(value)

核心特性

  1. 转换规则:遵循 JS 的隐式转换规则:

    • 原始类型转换

      原始类型转换结果示例
      Undefined"undefined"String(undefined)
      Null"null"String(null)
      Boolean"true""false"String(true) → "true"
      Number数字的字符串表示String(3.14) → "3.14"
      BigInt去掉末尾的 nString(10n) → "10"
      String原值(无变化)String("hi") → "hi"
      Symbol"Symbol(描述)"String(Sym()) → "Symbol()"
    • 对象类型转换

      1. 优先调用 toString() 方法

        js
        String({ toString: () => "custom" }) // "custom"
      2. toString() 时调用 valueOf()

        js
        String({ valueOf: () => 42 }) // "42"
      3. 默认对象转换

        js
        String({}) // "[object Object]"
        String([]) // "" (空数组)
        String([1, 2]) // "1,2"
    • 特殊值处理

      转换结果
      NaN"NaN"
      Infinity"Infinity"
      -0"0"
      空数组 []"" (空字符串)
      函数函数源码字符串
      Date 对象日期字符串
      RegExp 对象正则表达式字符串
  2. 对比 toString()

    特性String(value)value.toString()
    处理 null✅ 返回 "null"❌ 抛出 TypeError
    处理 undefined✅ 返回 "undefined"❌ 抛出 TypeError
    安全性✅ 总是安全❌ 原始值需包装
    数字转换✅ 直接转换❌ 需要指定基数
    使用场景通用类型转换对象自定义字符串表示
    js
    // 安全转换
    String(null)      // "null"
    null.toString()   // TypeError!
    
    // 数字转换
    String(15)        // "15"
    (15).toString()   // "15" (需括号)
    (15).toString(2)  // "1111" (二进制)

示例

  1. 自定义对象转换

    js
    class Product {
      constructor(name, price) {
        this.name = name;
        this.price = price;
      }
      toString() {
        return `${this.name} - ¥${this.price}`;
      }
    }
    
    const p = new Product("耳机", 299);
    String(p); // "耳机 - ¥299"

字符访问

charAt()

string.charAt()(index),用于获取指定索引位置的字符

  • indexnumber,要获取字符的索引位置。

    参数类型处理方式示例
    整数直接作为索引"A".charAt(0)"A"
    浮点数自动取整(非四舍五入)"AB".charAt(1.9)"B"
    负数返回空字符串"Hi".charAt(-1)""
    超出范围返回空字符串"OK".charAt(2)""
    非数值转换为 0"X".charAt("a")"X"
    未提供默认使用 0"Y".charAt()"Y"
  • 返回:

  • strstring,指定位置的字符或空字符串(当索引无效时)。返回的是 UTF-16 编码单元,而非完整字符。

语法特性

  1. 特殊字符处理

    • 代理对字符(如表情符号)

      js
      const rocket = "🚀";
      rocket.length;      // 2
      rocket.charAt(0);   // "\uD83D"(高代理项)
      rocket.charAt(1);   // "\uDE80"(低代理项)
    • 组合字符

      js
      const cafe = "café";  // "e" + 重音符组合
      cafe.charAt(3);      // "e"
      cafe.charAt(4);      // "\u0301"(重音符)

最佳实践

  1. 方法推荐

    • 简单 ASCII 文本优先使用 charAt()
    • 多语言/表情符号文本使用 at()Array.from()
    • 需要字符编码时使用 charCodeAt()/codePointAt()
  2. 索引验证:始终检查索引是否在有效范围内。

    js
    if (index >= 0 && index < str.length) {
      const char = str.charAt(index);
    }
  3. 处理复杂字符:对于代理对或组合字符,使用更现代的方法

    js
    // 获取完整字符的方式
    Array.from("🚀")[0]; // "🚀"
    "🚀".at(0);          // "🚀" (ES2022)
  4. 性能考虑:在循环中访问字符时,缓存字符串长度

    js
    const len = str.length;
    for (let i = 0; i < len; i++) {
      str.charAt(i);
    }
  5. 空值处理:确保输入是字符串类型

    js
    function safeCharAccess(input, index) {
      if (typeof input !== "string") return "";
      return input.charAt(index);
    }

示例

  1. 获取首字母

    js
    function getFirstChar(str) {
      return str.charAt(0);
    }
    getFirstChar("React"); // "R"
  2. 遍历字符串(不推荐用于复杂字符)

    js
    const str = "ABC";
    for (let i = 0; i < str.length; i++) {
      console.log(str.charAt(i));
    }
    // 输出: "A", "B", "C"
  3. 实现字符串反转

    js
    function reverseString(str) {
      let result = "";
      for (let i = str.length - 1; i >= 0; i--) {
        result += str.charAt(i);
      }
      return result;
    }
    reverseString("123"); // "321"
charCodeAt()

string.charCodeAt()(index?),用于获取指定索引位置字符的 UTF-16 编码值

  • index?number默认:0,要获取编码的字符位置。

    参数类型处理方式示例
    整数直接作为索引"A".charCodeAt(0)65
    浮点数自动取整(向下取整)"B".charCodeAt(0.9)66 (B 的 ASCII)
    负数返回 NaN"C".charCodeAt(-1)NaN
    超出范围返回 NaN"OK".charCodeAt(3)NaN
    非数值转换为 0"X".charCodeAt("a")88 (X 的 ASCII)
    未提供默认使用 0"Y".charCodeAt()89
  • 返回:

    • codenumber范围:0~65535整数,指定位置的 UTF-16 编码值,无效索引返回 NaN

语法特性

  1. Unicode 处理机制

    • 基本多文种平面 (BMP)

      js
      // U+0041 拉丁字母 A
      "A".charCodeAt(0);   // 65 (十六进制 0x0041)
      
      // U+4E2D 中文"中"
      "中".charCodeAt(0);  // 20013 (十六进制 0x4E2D)
    • 辅助平面字符 (代理对)

      js
      // U+1F680 火箭表情 🚀
      const rocket = "🚀";
      rocket.length;          // 2 (代理对)
      rocket.charCodeAt(0);   // 55357  (0xD83D, 高代理)
      rocket.charCodeAt(1);   // 56960  (0xDE80, 低代理)
    • 组合字符

      js
      // é = e(U+0065) + 重音符(U+0301)
      "é".charCodeAt(0);  // 101 (e)
      "é".charCodeAt(1);  // 769 (重音符)

最佳实践

  1. 空字符串处理

    js
    "".charCodeAt(0);   // NaN
    "".charCodeAt();     // NaN
  2. 无效索引防御

    js
    function safeCharCode(str, index) {
      if (index < 0 || index >= str.length) return -1;
      return str.charCodeAt(index);
    }
  3. 获取完整代理对码点

    js
    // 获取完整码点
    function getFullCodePoint(str, index) {
      const high = str.charCodeAt(index);
      if (high >= 0xD800 && high <= 0xDBFF && index + 1 < str.length) {
        const low = str.charCodeAt(index + 1);
        return (high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000;
      }
      return high;
    }
    getFullCodePoint("🚀", 0); // 128640 (0x1F680)
  4. 组合字符警告:重音字符返回多个编码值

    js
    // 重音字符返回多个编码值
    "café".charCodeAt(3); // 101 (e)
    "café".charCodeAt(4); // 769 (重音符)

示例

  1. 字符编码转换

    js
    function toHexString(str) {
      let hex = "";
      for (let i = 0; i < str.length; i++) {
        const code = str.charCodeAt(i);
        hex += "U+" + code.toString(16).toUpperCase().padStart(4, '0') + " ";
      }
      return hex.trim();
    }
    toHexString("A中"); // "U+0041 U+4E2D"
  2. ASCII 值检测

    js
    function isASCII(str) {
      for (let i = 0; i < str.length; i++) {
        if (str.charCodeAt(i) > 127) return false;
      }
      return true;
    }
    isASCII("Hello");  // true
    isASCII("Héllo");  // false
  3. 自定义字符串加密

    js
    function simpleEncrypt(text, key) {
      let result = "";
      for (let i = 0; i < text.length; i++) {
        const code = text.charCodeAt(i);
        result += String.fromCharCode(code ^ key); // ^: 按位异或()
      }
      return result;
    }
    const encrypted = simpleEncrypt("Secret", 42);
  4. 代理对检测

    js
    function isSurrogatePairAt(str, index) {
      const code = str.charCodeAt(index);
      return code >= 0xD800 && code <= 0xDBFF; // 高代理区域
    }
    
    isSurrogatePairAt("🚀", 0); // true
at()

string.at()(index?)ES2022,用于获取指定索引位置的字符,支持正负索引访问。

  • index?number,字符位置索引,支持负数(从末尾计数)。

    参数类型处理方式示例
    正整数从开头计数 (0-based)"ABC".at(1)"B"
    负整数从末尾计数 (-1 为最后字符)"XYZ".at(-1)"Z"
    浮点数自动取整(向零取整)"123".at(1.9)"2"
    超出范围返回 undefined"OK".at(3)undefined
    非数值转换为 0"X".at("a")"X"
    未提供默认使用 0"Y".at()"Y"
  • 返回:

  • strstring|undefined,指定位置的字符或 undefined(索引无效时)。

语法特性

  1. Unicode 处理特性

    • 代理对字符完整返回

      js
      "🚀".at(0);  // "🚀"(完整字符)
      "👨‍👩‍👧".at(0); // "👨"(首个字符,注意零宽连接符)
    • 组合字符独立返回

      js
      "café".at(3);  // "e"
      "café".at(4);  // "\u0301"(组合重音符)
    • 多码点字符处理

      js
      const flag = "🇨🇳"; // U+1F1E8 和 U+1F1F3
      flag.at(0);     // "🇨"(U+1F1E8)
      flag.at(1);     // "🇳"(U+1F1F3)
  2. 浏览器兼容性与 polyfill

    • 兼容性支持

      • 现代浏览器:Chrome 92+, Firefox 90+, Safari 15.4+
      • Node.js:16.6.0+
      • 不支持环境:IE, 旧版移动浏览器
    • Polyfill 实现

      js
      if (!String.prototype.at) {
        String.prototype.at = function(index) {
          // 处理非数值和未定义
          index = Math.trunc(index) || 0;
          
          // 处理负索引
          if (index < 0) index += this.length;
          
          // 边界检查
          if (index < 0 || index >= this.length) return undefined;
          
          // 返回字符(保持代理对完整)
          return String.fromCodePoint(this.codePointAt(index));
        };
      }

性能优化

  1. 避免在循环中重复计算长度

    js
    const len = str.length;
    for (let i = -len; i < len; i++) {
      str.at(i);
    }
  2. 优先用于负索引场景

    js
    // 优于
    str.charAt(str.length - 1);
    
    // 使用
    str.at(-1);
  3. 复杂字符处理

    js
    // 需要完整表情符号时
    Array.from(str)[0]; // 替代方案
  4. 输入验证

    js
    function safeAt(str, index) {
      if (typeof str !== "string") return undefined;
      return str.at(index);
    }

示例

  1. 基本使用

    js
    // 基础示例
    "JavaScript".at(0);   // "J"
    "前端".at(-1);        // "端"(负索引支持)
    "🚀".at(0);           // "🚀"(完整字符)
  2. 循环遍历(支持反向)

    js
    function reverseTraversal(str) {
      for (let i = -1; i >= -str.length; i--) {
        console.log(str.at(i));
      }
    }
    reverseTraversal("123"); // 输出 "3", "2", "1"

字符串查找

indexOf()

string.indexOf()(searchString,position?),区分大小写,用于查找子字符串首次出现的索引位置。从左向右进行,返回基于 0 的索引值。

  • searchStringstring,要查找的子字符串。

  • position?number默认:0,开始搜索的起始位置。

  • 返回:

  • indexnumber,首次出现的索引,未找到返回 -1

语法特性

  1. 特殊搜索行为

    • 空字符串处理

      js
      "Hello".indexOf("");    // 0(位置0存在空串)  
      "".indexOf("");         // 0  
      "ABC".indexOf("", 2);   // 2(从位置2开始空串存在)
    • Unicode 字符搜索

      js
      "café".indexOf("é");    // 3  
      "🚀火箭".indexOf("火");  // 2(🚀占2个编码单元)
    • 大小写敏感

      js
      "JavaScript".indexOf("script"); // -1(区分大小写)
  2. 搜索方法对比

最佳实践

  1. 统计子串出现次数:缓存长度提升循环性能。

    js
    function countOccurrences(str, substring) {  
      let count = 0;  
      let pos = 0;  
      const subLen = substring.length;  
      while ((pos = str.indexOf(substring, pos)) !== -1) {  
        count++;  
        pos += subLen; // // 跳过已匹配部分
      }  
      return count;  
    }  
    countOccurrences("abababa", "aba"); // 2
  2. 优先使用 includes() 检查存在性

    js
    // 更语义化的写法  
    if (str.includes(substring)) { ... }
  3. 处理非字符串输入:使用String()转换成字符串。

    js
    function safeIndexOf(input, search, position = 0) {  
      if (typeof input !== "string") input = String(input);  
      return input.indexOf(search, position);  
    }
  4. 大文本搜索优化:使用 Boyer-Moore 算法替代(第三方库)

    js
    // 使用 Boyer-Moore 算法替代(第三方库)  
    import { boyerMoore } from 'search-algorithms';  
    boyerMoore(largeText, pattern);
  5. 组合字符警告:先标准化字符串,再查找

    js
    "café".indexOf("é"); // 可能返回 -1(取决于组合方式)  
    
    // 解决方案:标准化字符串  
    "café".normalize().indexOf("é"); // 3

示例

  1. 检查子串存在性

    js
    function contains(str, substring) {  
      return str.indexOf(substring) !== -1;  
    }  
    contains("Hello World", "World"); // true
  2. 提取子串后的内容

    js
    function afterFirst(str, delimiter) {  
      const index = str.indexOf(delimiter);  
      return index === -1 ? str : str.slice(index + delimiter.length);  
    }  
    afterFirst("2023-06-16", "-"); // "06-16"
  3. 条件分支处理

    js
    const userAgent = navigator.userAgent;  
    let browser = "Unknown";  
    
    if (userAgent.indexOf("Chrome") !== -1) {  
      browser = "Chrome";  
    } else if (userAgent.indexOf("Firefox") !== -1) {  
      browser = "Firefox";  
    }
lastIndexOf()

string.lastIndexOf()(searchString,position?),区分大小写,用于查找子字符串最后一次出现的索引位置。搜索从字符串末尾向开头进行(从右向左),返回基于 0 的索引值。

  • searchStringstring,要查找的子字符串。

  • position?number默认:string.length-1类似indexOf(),搜索的结束位置。

  • 返回:

  • indexnumber,最后一次出现的索引,未找到返回 -1

语法特性

  1. 搜索方向:从右向左找。

    js
    // 从位置4向开头搜索  
    "ababab".lastIndexOf("ab", 4); // 4(从右向左找)
  2. 空字符串处理

    js
    "Hello".lastIndexOf("");    // 5(字符串末尾)  
    "".lastIndexOf("");         // 0  
    "ABC".lastIndexOf("", 1);   // 1(位置1存在空串)
  3. Unicode 支持

    js
    "café café".lastIndexOf("é");    // 8(第二个é)  
    "🚀🚀火箭".lastIndexOf("🚀");     // 2(第二个🚀的起始位置)
  4. 搜索方法对比

最佳实践类似indexOf()

示例

  1. 获取文件扩展名

    js
    function getFileExtension(filename) {  
      const dotIndex = filename.lastIndexOf(".");  
      return dotIndex === -1 ? "" : filename.slice(dotIndex + 1);  
    }  
    getFileExtension("archive.tar.gz"); // "gz"
  2. 提取域名

    js
    function getDomain(url) {  
      const protocolEnd = url.indexOf("://");  
      const domainStart = protocolEnd !== -1 ? protocolEnd + 3 : 0;  
      const domainEnd = url.indexOf("/", domainStart);  
      return url.slice(domainStart, domainEnd !== -1 ? domainEnd : undefined);  
    }  
    getDomain("https://example.com/path"); // "example.com"
  3. 替换最后一次出现的子串

    js
    function replaceLast(str, search, replace) {  
      const index = str.lastIndexOf(search);  
      return index === -1 ? str :  
        str.slice(0, index) + replace + str.slice(index + search.length);  
    }  
    replaceLast("a-b-c-d", "-", "."); // "a-b.c-d"
  4. 解析查询参数值

    js
    function getQueryParam(url, param) {  
      const paramStart = url.lastIndexOf(param + "=");  
      if (paramStart === -1) return null;  
      
      const valueStart = paramStart + param.length + 1;  
      const valueEnd = url.indexOf("&", valueStart);  
      return valueEnd === -1 ?  
        url.slice(valueStart) :  
        url.slice(valueStart, valueEnd);  
    }  
    getQueryParam("page.com?name=John&age=30", "age"); // "30"
  5. 验证文件类型

    js
    const ALLOWED_EXT = [".jpg", ".png"];  
    
    function isValidImage(filename) {  
      const lowerName = filename.toLowerCase();  
      return ALLOWED_EXT.some(ext =>  
        lowerName.lastIndexOf(ext) === filename.length - ext.length  
      );  
    }  
    isValidImage("photo.PNG"); // true
includes()

string.includes()(searchString, position?)ES2015,区分大小写,用于判断一个字符串是否包含在另一个字符串中

  • searchStringstring,要搜索的子字符串。

  • position?number默认:0,开始搜索的起始位置。

  • 返回:

  • isIncludesbooleans,包含返回 true,否则返回 false

语法特性

  1. 空字符串行为

    js
    "Hello".includes("");    // true(空字符串永远存在)  
    "".includes("");         // true
  2. Unicode 支持

    js
    "café".includes("é");    // true  
    "🚀火箭".includes("火");  // true
  3. 大小写敏感

    js
    "JavaScript".includes("script"); // false(区分大小写)
  4. 组合字符处理:需事先标准化。

    js
    const combined = "e\u0301";  // é  
    combined.includes("é");      // false(标准化后为 true)  
    combined.normalize().includes("é"); // true
  5. 搜索方法对比

性能优化

  1. 大小写不敏感优化:一次性转换避免重复计算。

    js
    // 一次性转换避免重复计算  
    function caseInsensitiveIncludes(str, search) {  
      const lowerStr = str.toLowerCase();  
      return lowerStr.includes(search.toLowerCase());  
    }
  2. 大文本搜索优化:限制搜索范围。

    js
    // 限制搜索范围  
    const MAX_SEARCH_LENGTH = 1000;  
    function safeIncludes(largeText, substring) {  
      return largeText.includes(  
        substring,  
        Math.max(0, largeText.length - MAX_SEARCH_LENGTH)  
      );  
    }
  3. 空值安全处理

    js
    function safeIncludes(input, search) {  
      if (typeof input !== "string") return false;  
      return input.includes(search);  
    }  
    safeIncludes(null, "error"); // false
  4. 组合字符处理

    js
    function unicodeIncludes(str, search) {  
      return str.normalize().includes(search.normalize());  
    }  
    unicodeIncludes("cafe\u0301", "é"); // true

示例

  1. 简单存在性检查

    js
    function hasKeyword(text, keyword) {  
      return text.includes(keyword);  
    }  
    hasKeyword("Error: File not found", "Error"); // true
  2. 权限验证

    js
    function checkPermission(userRoles) {  
      return userRoles.includes("admin") || userRoles.includes("editor");  
    }  
    checkPermission(["user", "editor"]); // true
  3. 搜索过滤

    js
    const products = ["iPhone", "iPad", "MacBook"];  
    const filtered = products.filter(product =>  
      product.toLowerCase().includes("ip")  
    );  
    // ["iPhone", "iPad"]
  4. 文件类型检查

    js
    function isImageFile(filename) {  
      const lower = filename.toLowerCase();  
      return [".png", ".jpg", ".gif"].some(ext => lower.includes(ext));  
    }  
    isImageFile("photo.PNG"); // true
  5. 带偏移量的检查

    js
    function isSecondOccurrence(text, word) {  
      const firstIndex = text.indexOf(word);  
      return firstIndex !== -1 && text.includes(word, firstIndex + 1);  
    }  
    isSecondOccurrence("a-b-a-c", "a"); // true
startsWith()

string.startsWith()(searchString, position?)ES2015,区分大小写,用于判断字符串是否以指定的子字符串开头

  • searchStringstring,要检查的前缀字符串。

  • position?number默认:0,开始搜索的起始位置。

  • 返回:

  • isStartsWithboolean,以该前缀开头返回 true,否则返回 false

核心特性

  1. 空字符串行为:空字符串永远匹配开头

    js
    "Hello".startsWith("");    // true(空字符串永远匹配开头)  
    "".startsWith("");         // true
  2. 大小写敏感

    js
    "JavaScript".startsWith("java"); // false(区分大小写)

示例

  1. 基本使用

    js
    "https://bank.com".startsWith("https://") // true
  2. 带偏移量的检查

    js
    "Hello World".startsWith("World", 6) // true

进阶扩展

  1. 大小写不敏感优化:统一转换为小写比较。

    js
    // 统一转换为小写比较  
    function caseInsensitiveStartsWith(str, prefix) {  
      return str.toLowerCase().startsWith(prefix.toLowerCase());  
    }  
    caseInsensitiveStartsWith("JavaScript", "JAVA"); // true
  2. 长前缀快速失败:先检查长度避免不必要的比较。

    js
    // 先检查长度避免不必要的比较  
    function safeStartsWith(str, prefix) {  
      if (prefix.length > str.length) return false;  
      return str.startsWith(prefix);  
    }  
    safeStartsWith("short", "very_long_prefix"); // false
  3. 空值安全处理

    js
    function safeStartsWith(input, prefix) {  
      if (typeof input !== "string") return false;  
      return input.startsWith(prefix);  
    }  
    safeStartsWith(null, "http"); // false
  4. 性能关键场景:避免在循环中重复转换大小写。

    js
    // 避免在循环中重复转换大小写  
    const lowerStr = str.toLowerCase();  
    for (const prefix of prefixes) {  
      lowerStr.startsWith(prefix.toLowerCase());  
    }
  5. 组合字符处理:事先使用 normalize() 标准化处理。

    js
    function unicodeStartsWith(str, prefix) {  
      return str.normalize().startsWith(prefix.normalize());  
    }  
    unicodeStartsWith("e\u0301cole", "école"); // true
endsWith()

string.endsWith()(searchString, length?)ES2015,区分大小写,用于判断字符串是否以指定的子字符串结尾

  • searchStringstring,要检查的后缀字符串。

  • length?number默认:string.length,指定字符串的有效长度。

    • 正整数:在指定长度内检查结尾。"abcabc".endsWith("ab", 3)false
    • 0:检查空字符串。"abc".endsWith("", 0)true
    • 负数:视为 0。"abc".endsWith("a", -5)false
    • 浮点数:取整(非四舍五入)。"abc".endsWith("c", 2.9)false
    • 超出长度:视为字符串长度。"abc".endsWith("c", 10)true
  • 返回:

  • isEndsWithboolean,以该后缀结尾返回 true,否则返回 false

核心特性

  1. 空字符串行为

    js
    "Hello".endsWith("");    // true(空字符串永远匹配结尾)  
    "".endsWith("");         // true
  2. 大小写敏感

    js
    "JavaScript".endsWith("script"); // false(区分大小写)
  3. Unicode 支持

    • 代理对:支持

      js
      "火箭🚀".endsWith("🚀");    // true
    • 组合字符处理:需标准化再使用

      js
      "café".endsWith("fé");   // false(é 是 e+重音符) 
      "café".normalize().endsWith("é"); // true

示例

  1. 基本使用

    js
    "JavaScript".endsWith("Script");      // true  
    "document.pdf".endsWith(".pdf");      // true  
    "前端开发".endsWith("开发");           // true
  2. 带长度限制的检查

    js
    function isLastName(str, name, maxLength) {  
      return str.endsWith(name, maxLength);  
    }  
    // 在10个字符内检查是否以"Smith"结尾  
    isLastName("John Smith", "Smith", 10); // true

进阶扩展:类似 startsWith()

字符串截取

slice()

string.slice()(startIndex, endIndex?),用于提取字符串的指定部分并返回新字符串。支持负索引,不自动交换参数,返回新字符串。

  • startIndexnumber,提取起始位置(包含)。假设 str = "ABCDE"

    • 正整数:从索引处开始。str.slice(1)"BCDE"
    • 负整数:从末尾计算(-1=最后字符)。str.slice(-3)"CDE"
    • 0:从头开始。str.slice(0)"ABCDE"
    • 浮点数:向零取整。str.slice(1.7)"BCDE"
    • 超出长度:返回空字符串。str.slice(10)""
    • NaN:视为 0。str.slice(NaN)"ABCDE"
  • endIndex?number,提取结束位置(不包含)。省略时提取到字符串末尾。假设 str = "ABCDE"

    • 正整数:提取到此索引前(不包含)。str.slice(1, 3)"BC"
    • 负整数:从末尾计算。str.slice(1, -1)"BCD"
    • 0:返回空字符串(因 end≤start)。str.slice(2, 0)""
    • 未提供:提取到字符串末尾。str.slice(2)"CDE"
    • 大于长度:视为字符串长度。str.slice(0, 10)"ABCDE"
  • 返回:

  • slicedStrstring,返回新字符串,包含提取的子字符串。

核心特性

  1. 负索引转换规则:转换为 len + index

    js
    const str = "ABCDE";  
    str.slice(-3);    // 等价于 str.slice(2) → "CDE"  
    str.slice(1, -2); // 等价于 str.slice(1, 3) → "BC"
  2. 不修改原字符串

    js
    const original = "Hello";  
    const sliced = original.slice(1);  
    console.log(original); // "Hello"(未改变)  
    console.log(sliced);   // "ello"
  3. Unicode 处理

    • 代理对字符(如表情符号):占据2个字符

      js
      "🚀火箭".slice(0, 1);  // "�"(无效字符)  
      "🚀火箭".slice(0, 2);  // "🚀"  
      "🚀火箭".slice(2, 4);  // "火箭"
    • 组合字符\u0301算一个字符

      js
      const cafe = "cafe\u0301"; // café  
      cafe.slice(0, 4); // "cafe"(不包含重音符)  
      cafe.slice(0, 5); // "café"

示例

  1. 提取文件名(无扩展名)

    js
    function getBaseName(filename) {  
      const dotIndex = filename.lastIndexOf(".");  
      return dotIndex === -1 ? filename : filename.slice(0, dotIndex);  
    }  
    getBaseName("archive.tar.gz"); // "archive.tar"
  2. 手机号脱敏处理

    js
    function maskPhone(phone) {  
      return phone.slice(0, 3) + "****" + phone.slice(-4);  
    }  
    maskPhone("13800138000"); // "138****8000"

进阶扩展

  1. 负索引性能低:直接使用正索引更快(避免负索引转换)

    js
    // 直接使用正索引更快(避免负索引转换)  
    const str = "Data";  
    str.slice(str.length - 3); // 优于 str.slice(-3)
  2. 大字符串优化:使用位置指针循环切片

    js
    // 避免重复切片大字符串  
    const largeText = "VeryLongText...";  
    // 错误:多次切片创建新字符串  
    const part1 = largeText.slice(0, 1000);  
    const part2 = largeText.slice(1000, 2000);  
    
    // 正确:使用位置指针  
    let pos = 0;  
    while (pos < largeText.length) {  
      const chunk = largeText.slice(pos, pos + 1000);  
      pos += 1000;  
    }
  3. 代理对安全处理:转换为数组处理代理对

    js
    function safeSlice(str, start, end) {  
      // 转换为数组处理代理对  
      return Array.from(str).slice(start, end).join("");  
    }  
    safeSlice("🚀火箭", 0, 1); // "🚀"
  4. 组合字符处理:标准化后再切片

    js
    // 标准化后再切片  
    "cafe\u0301".normalize().slice(0, 4); // "café"
  5. 避免链式调用

    js
    // 错误:多次创建临时字符串  
    str.slice(1).slice(0, 3);  
    
    // 正确:单次切片  
    str.slice(1, 4);
substring()

string.substring()(startIndex, endIndex?),用于提取两个指定索引之间的字符并返回新字符串。不支持负索引,自动参数交换,返回新字符串。

  • startIndexnumber,提取起始位置(包含)。

  • endIndex?number,提取结束位置(不包含)。省略时提取到字符串末尾。

    参数组合 (str = "ABCDE")等效调用结果说明
    substring(2)substring(2, 5)"CDE"省略 endIndex 时提取到末尾
    substring(2, 0)substring(0, 2)"AB"自动交换参数
    substring(-3, 2)substring(0, 2)"AB"负值视为 0
    substring(3, 10)substring(3, 5)"DE"超出长度视为字符串长度
    substring(NaN, 2)substring(0, 2)"AB"NaN 视为 0
    substring(2, undefined)substring(2)"CDE"undefined 视为未提供
  • 返回:

  • substringstring新字符串,包含提取的子字符串。

核心特性

  1. 对比 slice()

    • 不同:负值处理:不支持负索引,负值视为 0。

      js
      "ABCDE".substring(-5, 2);  // 转为 substring(0, 2) → "AB"  
      "ABCDE".substring(2, -1);  // 转为 substring(0, 2) → "AB"
    • 不同:自动参数交换

      js
      "ABCDE".substring(3, 1); // 自动转为 substring(1, 3) → "BC"
    • 相同:不修改原字符串

      js
      const str = "Hello";  
      str.substring(1, 3); // "el"  
      console.log(str);    // "Hello"(不变)
    • 相同:Unicode 处理

      js
      // 代理对字符
      "🚀火箭".substring(0, 2); // "🚀"(正确提取代理对)  
      "🚀火箭".substring(2, 4); // "火箭"  
      
      // 组合字符
      const cafe = "cafe\u0301"; // café  
      cafe.substring(0, 4);      // "cafe"(不包含重音符)  
      cafe.substring(0, 5);      // "café"(包含重音符)

进阶扩展

  1. 避免负参数:负参数触发转换逻辑(性能略低)

    js
    // 负参数触发转换逻辑(性能略低)  
    str.substring(1, -1); // 转为 str.substring(0, 1)  
    // 改用正索引  
    str.substring(0, 1);
  2. 大字符串优化:避免重复提取相同位置

    js
    // 避免重复提取相同位置  
    const largeText = "VeryLongText...";  
    // 错误:两次提取相同范围  
    const part1 = largeText.substring(0, 1000);  
    const part2 = largeText.substring(0, 1000);
  3. 组合字符处理:标准化后提取

    js
    // 标准化后提取  
    "cafe\u0301".normalize().substring(0, 4); // "café"
  4. 等值参数短路优化

    js
    function safeSubstring(str, start, end) {  
      if (start === end) return "";  
      return str.substring(start, end);  
    }  
    safeSubstring("ABC", 1, 1); // ""
  5. 替代方案选择

    • 需要负索引时使用 slice
    • 需要位置交换保障时用 substring
    js
    // 需要负索引时使用 slice  
    "End".slice(-3); // "End"  
    // 需要位置交换保障时用 substring  
    const start = 5, end = 2;  
    "Data".substring(start, end); // "Da"(自动交换)
substr()

string.substr()(startIndex, length?)已废弃,用于从指定位置开始提取指定长度的子字符串。支持负索引,返回新字符串。

  • startIndexnumber,提取起始位置(支持负索引)。

  • length?number提取的字符数。省略时提取到字符串末尾。

  • 返回:

  • substrstring,新字符串,包含提取的子字符串。

核心特性

  1. 支持负索引
  2. 返回新字符串
  3. 废弃原因
    1. 非 ECMAScript 标准(浏览器实现存在差异)
    2. 参数语义容易混淆(位置+长度 vs 起止位置)
    3. Unicode 支持不完善
  4. 对比 slice():第二个参数表示提取字符长度,而非结束索引。

示例

  1. 基本使用

    js
    const aString = "Mozilla";
    
    console.log(aString.substr(0, 1)); // 'M'
    console.log(aString.substr(1, 0)); // ''
    console.log(aString.substr(-1, 1)); // 'a'
    console.log(aString.substr(1, -1)); // ''
    console.log(aString.substr(-3)); // 'lla'
    console.log(aString.substr(1)); // 'ozilla'
    console.log(aString.substr(-20, 2)); // 'Mo'
    console.log(aString.substr(20, 2)); // ''

字符串修改

toUpperCase()

string.toUpperCase()(),用于将字符串中所有字符转换为大写形式。返回新字符串,支持 Unicode 和多语言字符转换。

  • 返回:

  • upperCasestring, 新字符串,全部字符转换为大写后的结果。

核心特性

  1. 不修改原字符串

  2. 非字母字符保留原样

    js
    "123!@#".toUpperCase();  // "123!@#"  
    "こんにちは".toUpperCase(); // "こんにちは"(日语假名不变)
  3. Unicode 支持

    字符类型转换示例
    拉丁字母"a" → "A"
    带重音字符"é" → "É"
    希腊字母"α" → "Α"
    西里尔字母"я" → "Я"
    特殊符号"ß" → "SS"(德语特殊规则)

示例

  1. 基本使用

    js
    // 基础示例  
    "hello".toUpperCase();      // "HELLO"  
    "café".toUpperCase();       // "CAFÉ"  
    "αβγ".toUpperCase();        // "ΑΒΓ"(希腊字母)
toLowerCase()

string.toLowerCase()(),用于将字符串中所有字符转换为小写形式。返回新字符串,支持 Unicode 和多语言字符转换。

  • 返回:

  • lowerCasestring,新字符串,全部字符转换为小写后的结果。

核心特性:类似 toUpperCase()

  1. 不修改原字符串

  2. 非字母字符保留原样

  3. Unicode 支持

示例

  1. 基本使用

    js
    // 基础示例  
    "HELLO".toLowerCase();      // "hello"  
    "CAFÉ".toLowerCase();       // "café"  
    "ΑΒΓ".toLowerCase();        // "αβγ"(希腊字母)
concat()

string.concat()(str1, str2, ..., strN),用于将多个字符串连接成一个新字符串。返回新字符串,功能与 + 操作符相似,支持链式调用。

  • str1, str2, ..., strNstring,要连接的字符串(至少一个,可多个)。示例("A".concat(...)):

    • 字符串:直接连接。"B""AB"
    • 非字符串:转换为字符串。123"A123"
    • 空值:转换为 "null"/"undefined"。null"Anull"
    • 数组:元素转换为字符串后连接。["B","C"]"AB,C"
    • 对象:调用 toString(){}"A[object Object]"
    • 未提供:返回原字符串副本。( )"A"
  • 返回:

  • newStrstring,新字符串,原始字符串与所有参数连接后的结果。

核心特性

  1. 不修改原字符串

  2. 自动类型转换

    js
    "Value: ".concat(42, true, null, undefined); // "Value: 42truenullundefined"
  3. 链式调用支持

    js
    "JS".concat(" is")  
        .concat(" awesome")  
        .concat("!"); // "JS is awesome!"

示例

  1. 基本使用

    js
    // 基础示例  
    "Hello".concat(" ", "World");  // "Hello World"  
    "前端".concat("开发");        // "前端开发"
  2. 模板字符串替代:现代语法更简洁

    js
    // 现代语法更简洁  
    const name = "John";  
    `Hello ${name}`;  // 优于 "Hello".concat(name)
repeat()

string.repeat()(count)ES2015,用于将字符串重复指定次数后返回新字符串。返回新字符串。

  • countnumber范围:0-∞,重复次数。

    • 浮点数:向下取整。

    • 负数/无穷数/未提供:报错(RangeError/RangeError/TypeError)。

  • 返回:

  • newStrstring,新字符串,原始字符串重复 count 次的结果。

核心特性

  1. 不修改原字符串

  2. 空字符串处理

  3. 支持 Unicode 字符

  4. 执行性能高

    js
    // 大量重复:引擎优化后仍高效  
    "0".repeat(1e6); // 现代引擎可处理

示例

  1. 基本使用

    js
    // 基础示例  
    "Hi".repeat(3);        // "HiHiHi"  
    "🚀".repeat(2);        // "🚀🚀"  
    "0".repeat(5);         // "00000"
trim()

string.trim()()ES2015,用于移除字符串两端的空白字符(包括空格、制表符\t\v、换行符\n等)。返回新字符串。

  • 返回:

  • newStrstring,新字符串,移除两端空白字符后的结果。

示例

  1. 基本使用

    js
    // 基础示例  
    "  Hello  ".trim();      // "Hello"  
    "\tText\n".trim();      // "Text"  
    " 全角空格 ".trim();   // "全角空格"(不移除)
trimStart()

string.trimStart()()ES2019,用于移除字符串开头的空白字符(包括空格、制表符、换行符等)。返回新字符串,别名 trimLeft()

  • 返回:

  • newStrstring,新字符串,移除开头空白字符后的结果。

示例

  1. 基本使用

    js
    // 基础示例  
    "  Hello".trimStart();      // "Hello"  
    "\tText\n".trimStart();    // "Text\n"  
    " 全角空格".trimStart();   // "全角空格"(保留)
trimEnd()

string.trimEnd()()ES2019,用于移除字符串结尾的空白字符(包括空格、制表符、换行符等)。返回新字符串,别名 trimRight()

  • 返回:

  • newStrstring,新字符串,移除结尾空白字符后的结果。

示例

  1. 基本使用

    js
    // 基础示例  
    "Hello  ".trimEnd();      // "Hello"  
    "Text\t\n".trimEnd();    // "Text"  
    "全角空格 ".trimEnd();   // "全角空格"(保留)
padStart()

string.padStart()(targetLength, padString?)ES2017,用于在字符串开头填充指定字符直到字符串达到目标长度。返回新字符串。

  • targetLengthnumber,填充后的目标长度(整数)。
  • padString?string默认:' ',填充字符。特殊值:
    • 多字符:截断填充。"A".padStart(3, "123")"12A"(取前两位)
    • 非字符串:转换为字符串。"A".padStart(3, true)"trA"(取前两位)
  • 返回:
  • newStrstring,新字符串,填充到目标长度后的结果。

核心特性

  1. 填充规则

    • 填充长度 = targetLength - 原字符串长度

      js
      // 填充长度 = targetLength - 原字符串长度  
      "X".padStart(3);        // "  X"(填充两个空格)  
      "XX".padStart(3, "Y");  // "YXX"(填充一个"Y")
    • 多字符填充截断,从前往后取字符。

      js
      // 多字符填充截断  
      "ID".padStart(4, "123"); // "12ID" → 需要3字符填充,取"123"  
      "ID".padStart(5, "12");  // "121ID" → 重复填充"12"("12"+"1")
  2. Unicode 支持

  3. 性能问题:大量填充:考虑预生成模板

    js
    // 少量填充:直接使用 padStart()  
    "1".padStart(3, "0"); // "001"  
    
    // 大量填充:考虑预生成模板  
    const ZERO_10K = "0".repeat(10000);  
    function padLarge(num, len) {  
      const str = num.toString();  
      return (ZERO_10K + str).slice(-len);  
    }

示例

  1. 基本使用

    js
    // 基础示例  
    "5".padStart(3, "0");      // "005"  
    "Hi".padStart(10, "-");    // "--------Hi"
padEnd()

string.padEnd()(targetLength, padString?)ES2017,用于在字符串结尾填充指定字符直到字符串达到目标长度。返回新字符串。

  • targetLengthnumber,填充后的目标长度(整数)。

  • padString?string默认:' ',填充字符。特殊值:

    • 多字符:截断填充。"A".padEnd(3, "123")"A12"(取前两位)
    • 非字符串:转换为字符串。"A".padEnd(3, true)"Atr"(取前两位)
  • 返回:

  • newStrstring,新字符串,填充到目标长度后的结果。

核心特性:类似 padStart()

  1. 填充规则

    • 填充长度 = targetLength - 原字符串长度

    • 多字符填充截断,从前往后取字符。

  2. Unicode 支持

  3. 性能问题:大量填充:考虑预生成模板

示例

  1. 基本使用

    js
    // 基础示例  
    "5".padEnd(3, "0");      // "500"  
    "Hi".padEnd(10, "-");    // "Hi--------"

正则表达式相关

match()

string.match()(regexp)支持正则,用于检索字符串中与正则表达式匹配的结果

  • regexpRegExp,正则表达式对象或可转换为正则的值。

  • 返回:

  • matchedArrarray|null,匹配结果(格式取决于 g 标志)。

    • 非全局匹配:返回第一个匹配的详细信息(包含分组信息)。
    • 全局匹配:返回所有匹配的子字符串数组。

核心特性

  1. 正则表达式

  2. 返回值详解

    • 非全局匹配(无 g 标志)

      js
      const result = "2023-06-16".match(/(\d{4})-(\d{2})-(\d{2})/);  
      /*  
      [  
        "2023-06-16",   // 完整匹配  
        "2023",         // 分组1  
        "06",           // 分组2  
        "16",           // 分组3  
        index: 0,       // 匹配起始位置  
        input: "2023-06-16",  // 原始字符串  
        groups: undefined    // 命名分组对象  
      ]  
      */
    • 全局匹配(有 g 标志)

      js
      "a1b2c3".match(/\d/g); // ["1", "2", "3"]
    • 命名分组支持(ES2018)

      js
      const result = "John Doe".match(/(?<first>\w+) (?<last>\w+)/);  
      /*  
      [  
        "John Doe",  
        "John",  
        "Doe",  
        index: 0,  
        input: "John Doe",  
        groups: { first: "John", last: "Doe" }  
      ]  
      */
    • 匹配失败

      js
      "abc".match(/\d/); // null
  3. Unicode 处理

    • 代理对字符

      js
      "🚀火箭".match(/./gu); // ["🚀", "火", "箭"](正确拆分)
    • Unicode 属性转义

      js
      "café".match(/\p{L}/gu); // ["c", "a", "f", "é"](匹配所有字母)

示例

  1. 基本使用

    js
    // 基础示例  
    "Hello World".match(/o/g);      // ["o", "o"](全局匹配)  
    "ID: 123".match(/\d+/);         // ["123", index: 4, input: "ID: 123", groups: undefined]
  2. 解析复杂字符串

    js
    function parseLogEntry(entry) {  
      const match = entry.match(/\[(\d{2}:\d{2})\] (\w+): (.+)/);  
      if (!match) return null;  
      
      return {  
        time: match[1],  
        level: match[2],  
        message: match[3]  
      };  
    }  
    parseLogEntry("[12:30] ERROR: File not found");  
    // { time: "12:30", level: "ERROR", message: "File not found" }

进阶扩展

  1. 多语言单词提取

    js
    function extractWords(text) {  
      return text.match(/\p{L}+/gu) || [];  // 匹配多语言中的单词(字)
    }  
    extractWords("こんにちは! Hello! 你好!"); // ["こんにちは", "Hello", "你好"]
  2. 粘滞模式\y

    js
    const regex = /\d+/y;  
    regex.lastIndex = 5;  
    "abc123def".match(regex); // ["3"](从索引5开始)
matchAll()

string.matchAll()(regexp)ES2020支持正则必须包含g,用于返回包含所有匹配正则表达式的结果及分组捕获组的迭代器

  • regexpRegExp,正则表达式对象(必须包含 g 标志)。

  • 返回:

  • resultIterator,迭代器,生成每个匹配的完整结果对象

核心特性

  1. 正则表达式

  2. 对比 match()

    • 提供了更完整的匹配信息(即使使用全局标志)

      js
       const matches = "a1b2c3".matchAll(/(\w)(\d)/g);  
      Array.from(matches);  
      /*  
      [  
        ["a1", "a", "1", index: 0, input: "a1b2c3", groups: undefined],  
        ["b2", "b", "2", index: 2, input: "a1b2c3", groups: undefined],  
        ["c3", "c", "3", index: 4, input: "a1b2c3", groups: undefined]  
      ]  
      */
    • 必须包含 g 标志:否则抛出 TypeError

  3. 返回值详解:迭代器生成的对象包含:

    • 匹配数组:完整匹配 + 捕获组
    • 标准属性
      • index:匹配起始位置
      • input:原始字符串
      • groups:命名捕获组对象
    • 新增属性(ES2022)
      • indices:匹配索引范围数组
      • indices.groups:命名分组索引
    js
    const result = "2023-06-16".matchAll(/(?<year>\d{4})-(?<month>\d{2})/gd);  
    const firstMatch = result.next().value;  
    /*  
    {  
      0: "2023-06",  
      1: "2023",  
      2: "06",  
      
      index: 0,  
      input: "2023-06-16",  
      groups: { year: "2023", month: "06" }, 
      
      indices: [  
        [0, 7],  
        [0, 4],  
        [5, 7],  
        groups: { year: [0,4], month: [5,7] }  
      ]  
    }  
    */

示例

  1. 提取复杂数据

    js
    function extractData(text) {  
      const regex = /(?<name>\w+):\s*(?<value>\d+)/gd;  
      return Array.from(text.matchAll(regex), match => match.groups);  
    }  
    
    extractData("A: 10, B: 20");  
    // [{ name: "A", value: "10" }, { name: "B", value: "20" }]

进阶扩展

  1. 使用迭代而非数组转换:效率更高

    js
    // 低效:Array.from(matches)  
    for (const match of text.matchAll(regex)) {  
      processMatch(match); // 直接处理  
    }
  2. 粘滞模式优化性能:从指定位置开始

    js
    const regex = /word/gy;  
    regex.lastIndex = 100; // 从指定位置开始  
    text.matchAll(regex);
  3. 索引范围处理(ES2022+)

    js
    function getMatchText(match) {  
      const [start, end] = match.indices[0];  
      return match.input.slice(start, end);  
    }

string.search()(regexp)支持正则,用于检索字符串中匹配正则表达式的第一个位置。与 indexOf() 类似但支持正则表达式。

  • regexpstring|RegExp,正则表达式对象或可转换为正则的值。

  • 返回:

  • indexnumber,首个匹配的起始索引(0起)或 -1(未匹配)。

核心特性

  1. 始终返回首个匹配位置g无效。

    js
    // 即使使用 g 标志也返回第一个匹配  
    "a1b2c3".search(/\d/g); // 1(不会返回后续匹配位置)
  2. 空搜索值行为

    js
    "abc".search("");  // 0(空字符串匹配开头)  
    "abc".search();    // 0(未提供参数视为空正则)
  3. 对比 indexOf()

    特性search()indexOf()
    参数类型正则/字符串仅字符串
    正则支持
    全局搜索❌(仅首个匹配)❌(需手动循环)
    性能略慢(需正则解析)更快
  4. 支持Unicode

示例

  1. 基本使用

    js
    // 基础示例  
    "JavaScript".search(/Script/);  // 4(匹配起始位置)  
    "Hello World".search(/\d/);     // -1(未找到数字)

进阶扩展

  1. 多语言文本检测

    js
    function isCJK(text) {  
      return text.search(/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}]/u) !== -1;  
    }  
    isCJK("日本語"); // true
  2. 提取匹配边界

    js
    function getFirstMatchRange(text, regex) {  
      const start = text.search(regex);  
      if (start === -1) return null;  
      const end = start + text.slice(start).match(regex)[0].length;  
      return [start, end];  
    }  
    getFirstMatchRange("ID: 123", /\d+/); // [4, 7]
replace()

string.replace()(searchValue, replaceValue)支持正则,用于替换字符串中匹配的子串。返回新字符串,支持字符串替换和正则表达式替换,并允许使用函数进行高级处理。

  • searchValuestring|RegExp,要替换的子串或正则表达式。以'apple'为例:

    • 字符串:仅替换第一个匹配项。"p" → 替换第一个 "p"
    • 正则表达式:根据标志替换(g 全局替换)。/p/g → 替换所有 "p"
    • 非正则对象:转换为字符串。123 → 匹配 "123"
  • replaceValuestring|function,替换文本或替换函数。以"2023"为例:

    • 字符串:直接替换(支持特殊替换模式:$&, $1 等)。"Year: $&" → "Year: 2023"
    • 替换函数:见替换函数详解,动态生成替换内容(参数:匹配文本、分组等)。(match) => +match + 1 → "2024"
    • 空值:转换为字符串。null → "null"
  • 返回:

  • newStrstring,新字符串,替换完成的结果。

核心特性

  1. 特殊替换模式

    模式描述示例("John Doe" 替换为 "$2, $1"
    $$插入 "$" 字符"$$1""$1"
    $&插入匹配的子串"Mr. $&""Mr. John Doe"
    $`插入匹配子串前的文本
    "Hello World!".replace(/(World)/, "[$`]")
    "[$`]""[Hello ]"(匹配 "World" 时)
    $'插入匹配子串后的文本
    "Hello World!".replace(/(World)/, "[$']")
    "[$']""[!]"(匹配 "World" 时)
    $n插入第 n 个分组(n=1-100)/(\w+) (\w+)/"$2, $1""Doe, John"
    $<name>插入命名分组(ES2018+)/(?<first>\w+) (?<last>\w+)/"$<last>, $<first>"
  2. 替换函数详解

    js
    (match, p1, p2, ..., offset, string, groups) => newString
    • matchstring,匹配的子串(相当于 $&)。
    • p1, p2, ...string,分组捕获内容(按顺序对应 $1, $2)。
    • offsetnumber,匹配子串在原字符串中的偏移量。
    • stringstring,原始字符串。
    • groupsobject,命名捕获组对象(ES2018+)。
    js
    // 函数替换示例  
    "border-top".replace(/-(\w)/g, (_, char) => char.toUpperCase());  
    // "borderTop"(转驼峰命名)

示例

  1. 基本使用

    js
    // 基础示例  
    "Hello World".replace("World", "JavaScript"); // "Hello JavaScript"
  2. 全局替换

    js
     "cat, dog, cat, bird".replace(/cat/g, "dog"); // "dog, dog, dog, bird"
  3. 分组引用:特殊替换模式

    js
    "2023-06-16".replace(/(\d{4})-(\d{2})-(\d{2})/, "$2/$3/$1"); // "06/16/2023"

进阶扩展

  1. 转义 HTML

    js
    function escapeHTML(str) {  
      return str.replace(/[&<>"']/g, char => ({  
        "&": "&amp;",  
        "<": "&lt;",  
        ">": "&gt;",  
        "\"": "&quot;",  
        "'": "&#39;"  
      }[char]));  
    }  
    escapeHTML(`<div>"Hi"</div>`); // "&lt;div&gt;&quot;Hi&quot;&lt;/div&gt;"
  2. 千分位数字

    js
    const num = "323123213.32232";
    const result = num.replace(/^(\d+)(\.\d+)$/, (match, integer, decimal) => {
      // 对整数部分应用千分位分隔符
      const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
      // 组合整数部分和小数部分
      return formattedInteger + decimal;
    });
    
    console.log(result);  // 输出: "323,123,213.32232"
  3. 命名分组支持

    js
    "2023-06".replace(/(?<year>\d{4})-(?<month>\d{2})/, "$<month>/$<year>"); // "06/2023"
  4. Unicode 安全替换

    js
    "🚀a🚀".replace(/\p{Emoji}/gu, "❤️"); // "❤️a❤️"(需 u 标志)
  5. 函数替换高级用法

    js
    "a1 b2 c3".replace(/(\w)(\d)/g, (match, letter, num) =>  
      String.fromCharCode(letter.charCodeAt(0) + parseInt(num))  
    ); // "b d f"
  6. 替换特殊字符

    js
    "$100".replace(/\$/g, "$$$$"); // "$$100"(转义 $ 字符)
replaceAll()

string.replaceAll()(searchValue, replaceValue)ES2021支持正则,用于全局替换字符串中所有匹配的子串。无需正则表达式即可实现全量替换。

  • searchValuestring|RegExp,要替换的子串或带 g 标志的正则表达式。

    • 注意:当 searchValue 为字符串时,全局替换所有匹配项。
    • 注意:当 searchValue 为正则时,必须包含 g 标志(否则抛出 TypeError)。
  • replaceValuestring|(match,p1,...,offset,string)=>string,替换文本或替换函数。

    • 注意:相比 replace()不接收分组参数(因字符串搜索无分组)。
    • 注意:正则搜索时函数参数与 replace() 相同(含分组)。
  • 返回:

  • newStrstring,新字符串,所有匹配项替换后的结果。

核心特性

  1. 对比 replace()
    • 全局字符串替换:不需要使用正则。
    • 首个字符串替换:需额外处理。
    • 正则搜索必须包含g:否则会抛出错误。
    • 函数参数:替换函数不接收分组参数groups。

示例

  1. 简单全局替换

    js
    const text = "Error: not found; Error: timeout";  
    text.replaceAll("Error", "Warning"); // "Warning: not found; Warning: timeout"
  2. 替换函数

    js
    const data = { red: "#FF0000", green: "#00FF00" };  
    "red,green,blue".replaceAll(/\w+/g, color => data[color] || color); // "#FF0000,#00FF00,blue"

进阶扩展

  1. 替换函数高级用法

    js
    "a1 b2 c3".replaceAll(/\d/g, (match, offset) =>  
      offset % 2 === 0 ? match : "X"  
    ); // "aX b2 cX"
  2. 转义特殊字符

    js
    function escapeRegExp(string) {  
      return string.replaceAll(/[.*+?^${}()|\[\]\\]/g, '\\$&');  
    }  
    const searchText = escapeRegExp("file.txt");  
    new RegExp(searchText); // 安全创建正则
split()

string.split()(separator?, limit?)支持正则,用于将字符串分割为子字符串数组。支持限制返回数组长度。

  • separator?string|RegExp,分割点(字符串或正则),未提供时默认返回整个字符串的数组。以 "a-b-c" 为例:

    • 字符串:按字面值分割。"-"["a","b","c"]
    • 空字符串:每个字符分割。""["a","-","b","-","c"]
    • 正则表达式:按匹配模式分割。/[-]/["a","b","c"]
    • 未提供:返回包含整个字符串的数组。( )["a-b-c"]
    • 不匹配值:返回包含整个字符串的数组。"x"["a-b-c"]
  • limit?number,返回数组的最大长度(超过部分被丢弃)。

  • 返回:

  • arrarray,数组,分割后的子字符串集合。

核心特性

  1. 空分隔符行为:每个字符分割

    js
    "hello".split("");  // ["h","e","l","l","o"]  
    "🚀火".split("");    // ["\uD83D", "\uDE80", "火"](代理对拆分)
  2. 捕获组处理(正则):捕获的分组也会返回

    js
    "2023-06-16".split(/(-)/);  // ["2023", "-", "06", "-", "16"]
  3. Unicode 安全分割:使用 u 标志避免代理对拆分

    js
    // 默认代理对拆分
    "🚀火".split("");    // ["\uD83D", "\uDE80", "火"]
    
    // 使用 u 标志避免代理对拆分,(?:) 表示捕获空值
    "🚀火".split(/(?:)/u);       // ["🚀", "火"]

示例

  1. 基本使用

    js
    // 基础示例  
    "apple,orange,banana".split(",");  // ["apple", "orange", "banana"]  
    "2023-06-16".split(/-/);          // ["2023", "06", "16"]
  2. 移除空项

    js
    "a,,b".split(",").filter(s => Boolean(s)); // ["a", "b"]

其他

localeCompare()

string.localeCompare()(compareString,locales?,options?),用于根据当前语言环境比较两个字符串的排序顺序。提供本地化的字符串排序能力,支持多语言排序规则(如德语、中文等)。

  • compareStringstring,被比较的字符串。

  • locales?string|array,语言标签(字符串或数组),如"de"、"zh"、"en"等。

  • options?object,配置对象(敏感度、大小写处理等)。

    • sensitivitybase|accent|case|variant,默认:variant`,比较敏感度。
    • ignorePunctuationboolean默认:false,是否忽略标点。
    • numericboolean默认:false,是否按数字顺序("10" > "2")。
    • caseFirstupper|lower|false默认:false,大小写优先级。
    • usagesort|search默认:sort,排序或搜索模式。
  • 返回:

  • resultnumber负数(前<后),0(相等),正数(前>后)。

核心特性

  1. 语言敏感排序

    js
    // 德语:ä 在 z 前  
    "ä".localeCompare("z", "de"); // -1  
    
    // 瑞典语:ä 在 z 后  
    "ä".localeCompare("z", "sv"); // 1
  2. 数字排序

    js
    // 普通排序  
    "10".localeCompare("2"); // -1("10" 在 "2" 前,按字符串)  
    
    // 数字模式排序  
    "10".localeCompare("2", undefined, { numeric: true }); // 1(10 > 2)
  3. 大小写处理:默认大写字母排后。

    js
    // 默认大小写敏感  
    "A".localeCompare("a"); // >0(大写字母排后)  
    
    // 忽略大小写  
    "A".localeCompare("a", undefined, { sensitivity: "base" }); // 0

示例

  1. 基本使用

    js
    // 基础示例  
    "ä".localeCompare("z", "de"); // -1(德语中 ä 排在 z 前)  
    "二".localeCompare("一", "zh"); // 1(中文数字排序)
  2. 用户列表按姓名字母排序

    js
    const users = [  
      { name: "张伟" },  
      { name: "王芳" },  
      { name: "李娜" }  
    ];  
    
    users.sort((a, b) =>  
      a.name.localeCompare(b.name, "zh-CN")  
    );  
    // 李娜, 王芳, 张伟(中文拼音顺序)
  3. 文件名数字排序

    js
    const files = ["file10", "file2", "file1"];  
    files.sort((a, b) =>  
      a.localeCompare(b, undefined, { numeric: true })  
    );  
    // ["file1", "file2", "file10"]
normalize()

string.normalize()(form?)ES2015,用于将字符串转换为 Unicode 标准化形式。它解决字符的多种表示方式问题(如组合字符 vs 预组合字符)。

  • form?NFC|NFD|NFKC|NFKD默认:NFC,标准化形式。

    • NFCNormalization Form C (Composition)默认,先分解再组合,优先使用预组合字符(如 é 而非 e + ´)。
    • NFDNormalization Form D (Decomposition),完全分解:分离基本字符和组合标记(如 ée + ´)。
    • NFKCNFK Casefold Composition,兼容组合:移除格式差异(如 ff)。
    • NFKDNFK Casefold Decomposition,兼容分解:移除格式差异并分解字符。
  • 返回:

  • newStrstring,新字符串,Unicode 标准化后的结果。

核心特性

  1. 解决等价表示问题:组合字符序列 vs 预组合字符

    js
    // 组合字符序列 vs 预组合字符  
    const composed = "é";        // U+00E9  
    const decomposed = "e\u0301"; // U+0065 + U+0301  
    
    composed === decomposed; // false  
    composed.normalize() === decomposed.normalize(); // true(NFC 下)
  2. 兼容形式处理

    js
    // 连字标准化  
    "ffi".normalize("NFKC"); // "ffi"  
    
    // 全角数字标准化  
    "123".normalize("NFKC"); // "123"
  3. 不修改原字符串

    js
    // 不修改原字符串  
    const str = "cafe\u0301";  
    str.normalize(); // "café"  
    console.log(str); // "café"(未变)
  4. Unicode 标准化形式对比

    形式类型字符存储方式典型用途
    NFC组合尽量使用预组合字符显示、存储
    NFD分解分离基本字符+组合标记文本处理、搜索
    NFKC兼容组合移除格式差异并组合标识符比较、数据清洗
    NFKD兼容分解移除格式差异并分解拼音处理、深度文本分析

示例

  1. 基本使用

    js
    // 基础示例  
    "café".normalize();         // "café"(NFC 形式)  
    "cafe\u0301".normalize();   // "café"(组合字符转预组合)
  2. Unicode 符号表

进阶扩展

  1. 用户名规范化

    js
    function normalizeUsername(name) {  
      return name.normalize("NFKC")  
        .replace(/\p{Mark}/gu, "") // 移除所有组合标记  
        .toLowerCase();  
    }  
    
    normalizeUsername("Jŏhņ_ß"); // "john_ss"
  2. 拼音处理

    js
    function getPinyinTones(text) {  
      return text.normalize("NFD")  
        .replace(/[\u0300-\u036f]/g, tone =>  
          ({ "\u0304": "1", "\u0301": "2", "\u030C": "3", "\u0300": "4" }[tone] || "")  
        );  
    }  
    
    getPinyinTones("mā má mǎ mà"); // "ma1 ma2 ma3 ma4"
  3. 长度差异处理

    js
    "é".length; // 1  
    "é".normalize("NFD").length; // 2
  4. 代理对保留

    js
    "🚀".normalize("NFD"); // "🚀"(代理对不受影响)
  5. 正则表达式结合

    js
    const regex = /^[\p{L}\p{N}]+$/u;  
    function isAlphanumeric(str) {  
      return regex.test(str.normalize("NFKD"));  
    }  
    isAlphanumeric("ABC123"); // true(全角转半角)