String

Baseline 广泛可用 *

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2015 年 7 月⁩以来,各浏览器均已提供此特性。

* 此特性的某些部分可能存在不同级别的支持。

String 对象用于表示和操作字符序列。

描述

字符串对于存储文本形式的数据非常有用。字符串最常用的操作包括:检查其length(长度);使用 ++= 字符串运算符构建和连接它们;使用 indexOf() 方法检查子字符串是否存在或其位置;或者使用 substring() 方法提取子字符串。

创建字符串

字符串可以通过字符串字面量作为原始值创建,也可以使用 String() 构造函数作为对象创建。

js
const string1 = "A string primitive";
const string2 = 'Also a string primitive';
const string3 = `Yet another string primitive`;
js
const string4 = new String("A String object");

字符串原始值和字符串对象在许多行为上是相同的,但也有其他重要的区别和注意事项。请参阅下面的“字符串原始值和字符串对象”。

字符串字面量可以使用单引号或双引号指定,它们被视为相同,也可以使用反引号字符 `。最后一种形式指定了模板字面量:通过这种形式,你可以插入表达式。有关字符串字面量语法的更多信息,请参阅词法语法

字符访问

有两种方法可以访问字符串中的单个字符。第一种是 charAt() 方法。

js
"cat".charAt(1); // gives value "a"

另一种方法是将字符串视为类数组对象,其中单个字符对应于数字索引。

js
"cat"[1]; // gives value "a"

当使用方括号表示法进行字符访问时,尝试删除或为这些属性赋值将不会成功。涉及的属性既不可写入也不可配置。(有关更多信息,请参阅 Object.defineProperty()。)

比较字符串

使用小于和大于运算符来比较字符串。

js
const a = "a";
const b = "b";
if (a < b) {
  // true
  console.log(`${a} is less than ${b}`);
} else if (a > b) {
  console.log(`${a} is greater than ${b}`);
} else {
  console.log(`${a} and ${b} are equal.`);
}

请注意,所有比较运算符,包括 =====,都对字符串进行大小写敏感的比较。一种常见的进行大小写不敏感字符串比较的方法是,在比较之前将两者转换为相同的大小写(大写或小写)。

js
function areEqualCaseInsensitive(str1, str2) {
  return str1.toUpperCase() === str2.toUpperCase();
}

选择使用 toUpperCase() 还是 toLowerCase() 转换大多是随意的,而且当超出拉丁字母表时,两者都不能完全健壮。例如,德语小写字母 ßss 都会被 toUpperCase() 转换为 SS,而土耳其字母 ı 如果不特别使用 toLocaleLowerCase("tr"),则会被 toLowerCase() 错误地报告为与 I 不等。

js
const areEqualInUpperCase = (str1, str2) =>
  str1.toUpperCase() === str2.toUpperCase();
const areEqualInLowerCase = (str1, str2) =>
  str1.toLowerCase() === str2.toLowerCase();

areEqualInUpperCase("ß", "ss"); // true; should be false
areEqualInLowerCase("ı", "I"); // false; should be true

一个区域设置感知且健壮的测试大小写不敏感相等性的解决方案是使用 Intl.Collator API 或字符串的 localeCompare() 方法——它们共享相同的接口——并将 sensitivity 选项设置为 "accent""base"

js
const areEqual = (str1, str2, locale = "en-US") =>
  str1.localeCompare(str2, locale, { sensitivity: "accent" }) === 0;

areEqual("ß", "ss", "de"); // false
areEqual("ı", "I", "tr"); // true

localeCompare() 方法以类似于 strcmp() 的方式启用字符串比较——它允许以区域设置感知的方式对字符串进行排序。

字符串原始值和字符串对象

请注意,JavaScript 区分 String 对象和原始字符串值。(BooleanNumbers 也是如此。)

字符串字面量(由双引号或单引号表示)以及在非构造函数上下文(即,不使用 new 关键字调用)中从 String 调用返回的字符串都是原始字符串。在需要对原始字符串调用方法或进行属性查找的上下文中,JavaScript 会自动包装原始字符串,并在包装对象上调用方法或执行属性查找。

js
const strPrim = "foo"; // A literal is a string primitive
const strPrim2 = String(1); // Coerced into the string primitive "1"
const strPrim3 = String(true); // Coerced into the string primitive "true"
const strObj = new String(strPrim); // String with new returns a string wrapper object.

console.log(typeof strPrim); // "string"
console.log(typeof strPrim2); // "string"
console.log(typeof strPrim3); // "string"
console.log(typeof strObj); // "object"

警告:你很少会发现自己将 String 作为构造函数使用。

字符串原始值和 String 对象在使用 eval() 时也会产生不同的结果。传递给 eval 的原始值被视为源代码;String 对象被视为所有其他对象一样,通过返回对象。例如:

js
const s1 = "2 + 2"; // creates a string primitive
const s2 = new String("2 + 2"); // creates a String object
console.log(eval(s1)); // returns the number 4
console.log(eval(s2)); // returns the string "2 + 2"

由于这些原因,当代码遇到 String 对象而预期原始字符串时,代码可能会中断,尽管通常作者不必担心这种区别。

String 对象始终可以使用 valueOf() 方法转换为其原始对应项。

js
console.log(eval(s2.valueOf())); // returns the number 4

字符串强制转换

许多期望字符串的内置操作会首先将其参数强制转换为字符串(这很大程度上是 String 对象与字符串原始值行为相似的原因)。该操作可以总结如下:

在 JavaScript 中有几种方法可以达到几乎相同的效果。

  • 模板字面量`${x}` 为嵌入的表达式执行上述完全相同的字符串强制转换步骤。
  • String() 函数:String(x) 使用相同的算法转换 x,不同之处在于 Symbols 不会抛出 TypeError,而是返回 "Symbol(description)",其中 description 是 Symbol 的描述
  • 使用 + 运算符"" + x 将其操作数强制转换为原始值而不是字符串,并且对于某些对象,其行为与正常字符串强制转换完全不同。有关更多详细信息,请参阅其参考页面

根据你的用例,你可能希望使用 `${x}`(模仿内置行为)或 String(x)(处理 Symbol 值而不抛出错误),但不应使用 "" + x

UTF-16 字符、Unicode 码点和字形簇

字符串从根本上表示为 UTF-16 码元序列。在 UTF-16 编码中,每个码元正好是 16 位长。这意味着最多有 216,即 65536 个字符可以表示为单个 UTF-16 码元。这个字符集被称为基本多语言平面(BMP),包括拉丁字母、希腊字母、西里尔字母以及许多东亚字符等最常见字符。每个码元都可以用 \u 后跟四个十六进制数字在字符串中书写。

然而,整个 Unicode 字符集远大于 65536。额外的字符在 UTF-16 中以代理对的形式存储,代理对是由两个 16 位码元表示一个字符。为避免歧义,代理对的两个部分必须介于 0xD8000xDFFF 之间,并且这些码元不用于编码单个码元字符。(更精确地说,前导代理,也称为高代理码元,其值介于 0xD8000xDBFF(含)之间,而尾随代理,也称为低代理码元,其值介于 0xDC000xDFFF(含)之间。)每个 Unicode 字符,由一个或两个 UTF-16 码元组成,也称为Unicode 码点。每个 Unicode 码点可以用 \u{xxxxxx} 在字符串中书写,其中 xxxxxx 表示 1-6 个十六进制数字。

“孤立代理”是满足以下描述之一的 16 位码元:

  • 它在 0xD8000xDBFF 范围内(即,是前导代理),但它是字符串中的最后一个码元,或者下一个码元不是尾随代理。
  • 它在 0xDC000xDFFF 范围内(即,是尾随代理),但它是字符串中的第一个码元,或者前一个码元不是前导代理。

孤立代理不表示任何 Unicode 字符。尽管大多数 JavaScript 内置方法都能正确处理它们,因为它们都是基于 UTF-16 码元工作的,但孤立代理在与其他系统交互时通常不是有效值——例如,encodeURI() 会对孤立代理抛出 URIError,因为 URI 编码使用 UTF-8 编码,而 UTF-8 没有孤立代理的编码。不包含任何孤立代理的字符串称为格式良好的字符串,可以安全地与不处理 UTF-16 的函数(例如 encodeURI()TextEncoder)一起使用。你可以使用 isWellFormed() 方法检查字符串是否格式良好,或使用 toWellFormed() 方法清理孤立代理。

除了 Unicode 字符之外,还有一些 Unicode 字符序列应被视为一个视觉单元,称为字形簇。最常见的情况是表情符号:许多具有多种变体的表情符号实际上是由多个表情符号组成的,通常通过 <ZWJ> (U+200D) 字符连接。

你必须注意你正在迭代的字符级别。例如,split("") 将按 UTF-16 码元分割,并将代理对分开。字符串索引也指的是每个 UTF-16 码元的索引。另一方面,[Symbol.iterator]() 按 Unicode 码点迭代。迭代字形簇将需要一些自定义代码。

js
"😄".split(""); // ['\ud83d', '\ude04']; splits into two lone surrogates

// "Backhand Index Pointing Right: Dark Skin Tone"
[..."👉🏿"]; // ['👉', '🏿']
// splits into the basic "Backhand Index Pointing Right" emoji and
// the "Dark skin tone" emoji

// "Family: Man, Boy"
[..."👨‍👦"]; // [ '👨', '‍', '👦' ]
// splits into the "Man" and "Boy" emoji, joined by a ZWJ

// The United Nations flag
[..."🇺🇳"]; // [ '🇺', '🇳' ]
// splits into two "region indicator" letters "U" and "N".
// All flag emojis are formed by joining two region indicator letters

构造函数

String()

创建 String 对象。当作为函数调用时,它返回类型为 String 的原始值。

静态方法

String.fromCharCode()

返回使用指定的 Unicode 值序列创建的字符串。

String.fromCodePoint()

返回使用指定的码点序列创建的字符串。

String.raw()

返回从原始模板字符串创建的字符串。

实例属性

这些属性在 String.prototype 上定义,并由所有 String 实例共享。

String.prototype.constructor

创建实例对象的构造函数。对于 String 实例,初始值是 String 构造函数。

这些属性是每个 String 实例的自有属性。

length

反映字符串的 length(长度)。只读。

实例方法

String.prototype.at()

返回指定 index 处的字符(正好一个 UTF-16 码元)。接受负整数,负整数表示从字符串末尾开始倒数。

String.prototype.charAt()

返回指定 index 处的字符(正好一个 UTF-16 码元)。

String.prototype.charCodeAt()

返回指定 index 处的 UTF-16 码元值的数字。

String.prototype.codePointAt()

返回一个非负整数 Number,它是从指定 pos 开始的 UTF-16 编码码点的码点值。

String.prototype.concat()

合并两个(或更多)字符串的文本并返回一个新字符串。

String.prototype.endsWith()

判断一个字符串是否以字符串 searchString 的字符结尾。

String.prototype.includes()

判断调用字符串是否包含 searchString

String.prototype.indexOf()

返回此字符串中 searchValue 第一次出现的索引,如果未找到则返回 -1

String.prototype.isWellFormed()

返回一个布尔值,指示此字符串是否包含任何孤立代理

String.prototype.lastIndexOf()

返回此字符串中 searchValue 最后一次出现的索引,如果未找到则返回 -1

String.prototype.localeCompare()

返回一个数字,指示参考字符串 compareString 在排序顺序中是位于给定字符串之前、之后还是与之等效。

String.prototype.match()

用于将正则表达式 regexp 与字符串进行匹配。

String.prototype.matchAll()

返回所有 regexp 匹配项的迭代器。

String.prototype.normalize()

返回调用字符串值的 Unicode 标准化形式。

String.prototype.padEnd()

用给定字符串从末尾填充当前字符串,并返回一个长度为 targetLength 的新字符串。

String.prototype.padStart()

用给定字符串从开头填充当前字符串,并返回一个长度为 targetLength 的新字符串。

String.prototype.repeat()

返回一个由对象元素重复 count 次组成的字符串。

String.prototype.replace()

用于使用 replaceWith 替换 searchFor 的出现。searchFor 可以是字符串或正则表达式,replaceWith 可以是字符串或函数。

String.prototype.replaceAll()

用于使用 replaceWith 替换所有 searchFor 的出现。searchFor 可以是字符串或正则表达式,replaceWith 可以是字符串或函数。

String.prototype.search()

在正则表达式 regexp 和调用字符串之间搜索匹配。

String.prototype.slice()

提取字符串的一部分并返回一个新字符串。

String.prototype.split()

返回一个字符串数组,该数组是通过在子字符串 sep 出现的位置拆分调用字符串而填充的。

String.prototype.startsWith()

判断调用字符串是否以字符串 searchString 的字符开头。

String.prototype.substr() 已弃用

返回字符串的一部分,从指定索引开始,并在此后延伸给定数量的字符。

String.prototype.substring()

返回一个新字符串,其中包含调用字符串中从(或介于)指定索引(或索引之间)的字符。

String.prototype.toLocaleLowerCase()

字符串中的字符被转换为小写,同时遵守当前区域设置。

对于大多数语言,这将返回与 toLowerCase() 相同的结果。

String.prototype.toLocaleUpperCase()

字符串中的字符被转换为大写,同时遵守当前区域设置。

对于大多数语言,这将返回与 toUpperCase() 相同的结果。

String.prototype.toLowerCase()

返回转换为小写的调用字符串值。

String.prototype.toString()

返回表示指定对象的字符串。覆盖 Object.prototype.toString() 方法。

String.prototype.toUpperCase()

返回转换为大写的调用字符串值。

String.prototype.toWellFormed()

返回一个字符串,其中此字符串的所有孤立代理都替换为 Unicode 替换字符 U+FFFD。

String.prototype.trim()

从字符串的开头和结尾修剪空格。

String.prototype.trimEnd()

从字符串的末尾修剪空格。

String.prototype.trimStart()

从字符串的开头修剪空格。

String.prototype.valueOf()

返回指定对象的原始值。覆盖 Object.prototype.valueOf() 方法。

String.prototype[Symbol.iterator]()

返回一个新的迭代器对象,该对象遍历字符串值的码点,将每个码点作为字符串值返回。

HTML 包装器方法

警告:已弃用。避免使用这些方法。

它们的用途有限,因为它们基于一个非常旧的 HTML 标准,并且只提供了当前可用 HTML 标签和属性的子集。其中许多今天创建的是已弃用或非标准的标记。此外,它们在没有任何验证或清理的情况下进行字符串连接,这使得它们在直接使用 innerHTML 插入时可能构成安全威胁。请改用 DOM API,例如 document.createElement()

String.prototype.anchor() 已弃用

<a name="name"> (超文本目标)

String.prototype.big() 已弃用
<big>

<blink>

String.prototype.bold() 已弃用
<b>
String.prototype.fixed() 已弃用
<tt>
String.prototype.fontcolor() 已弃用

<font color="color">

String.prototype.fontsize() 已弃用

<font size="size">

String.prototype.italics() 已弃用
<i>

<a href="url"> (链接到 URL)

String.prototype.small() 已弃用
<small>
String.prototype.strike() 已弃用
<strike>
String.prototype.sub() 已弃用
<sub>
String.prototype.sup() 已弃用
<sup>

请注意,这些方法不检查字符串本身是否包含 HTML 标签,因此可能会创建无效 HTML。

js
"</b>".bold(); // <b></b></b>

它们唯一的转义是将属性值中的 "(对于 anchor()fontcolor()fontsize()link())替换为 &quot;

js
"foo".anchor('"Hello"'); // <a name="&quot;Hello&quot;">foo</a>

示例

字符串转换

String() 函数比调用值的 toString() 方法更能可靠地将值转换为字符串,因为前者在用于 nullundefined 时也能工作。例如:

js
// You cannot access properties on null or undefined

const nullVar = null;
nullVar.toString(); // TypeError: Cannot read properties of null
String(nullVar); // "null"

const undefinedVar = undefined;
undefinedVar.toString(); // TypeError: Cannot read properties of undefined
String(undefinedVar); // "undefined"

规范

规范
ECMAScript® 2026 语言规范
# sec-string-objects

浏览器兼容性

另见