介绍
字符串适用于存储可以以文本形式表示的数据。一些最常用的字符串操作包括:检查字符串长度、使用字符串运算符 + 和 += 构建和连接字符串、使用 indexOf() 方法检查子字符串的存在或位置,以及使用 substring() 方法提取子字符串。.
创建字符串
字符串可以通过字符串字面量直接创建,也可以使用 String() 构造函数创建为对象:
const string1 = "A string primitive";
const string2 = 'Also a string primitive';
const string3 = `Yet another string primitive`;const string4 = new String("A String object");
字符串基本类型和字符串对象有很多共同的行为,但它们也存在其他一些重要的区别和注意事项。请参阅下文“字符串基本类型和字符串对象”。.
字符串字面量可以使用单引号或双引号指定,两者效果相同,也可以使用反引号 `。最后一种形式指定了一个实际的模式:您可以使用这种形式插入表达式。有关字符串字面量语法的更多信息,请参阅词法语法。.
角色访问
有两种方法可以访问字符串中的字符。第一种是 charAt() 方法:
"cat".charAt(1); // gives value "a"
另一种方法是将字符串视为类似数组的对象,其中每个字符对应于一个数字索引:
"cat"[1]; // gives value "a"
使用方括号表示法访问字符时,尝试删除或赋值这些属性将会失败。这些属性既不可写也不可设置。(更多信息请参阅 Object.defineProperty()。)
比较字符串
使用小于号和大于号运算符比较字符串:
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.`);
}请注意,所有比较运算符(包括 === 和 ==)都会区分字符串的大小写。一种常见的区分大小写比较方法是在比较之前将两个字符串转换为相同的字母(大写或小写)。.
function areEqualCaseInsensitive(str1, str2) {
return str1.toUpperCase() === str2.toUpperCase();
}使用 `toUpperCase()` 还是 `toLowerCase()` 进行转换很大程度上是任意的,而且当扩展到拉丁字母以外的字母时,这两种方法都不够稳健。例如,德语小写字母 ß 和 ss 都会被 `toUpperCase()` 转换为 SS,而土耳其字母 ı 则会被 `toLowerCase()` 错误地报告为不等于 I,除非明确使用 `toLocaleLowerCase("tr")`。.
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() 方法——它们具有相同的接口——并将敏感度选项设置为“accent”或“base”。.
const areEqual = (str1, str2, locale = "en-US") =>
str1.localeCompare(str2, locale, { sensitivity: "accent" }) === 0;
areEqual("ß", "ss", "de"); // false
areEqual("ı", "I", "tr"); // truelocaleCompare() 方法允许以类似于 strcmp() 的方式比较字符串——这使得可以以区域设置感知的方式对字符串进行排序。.
原始字符串和字符串对象
请注意,JavaScript 会区分字符串对象和原始字符串值。(布尔值和数字也是如此。)
字符串字面量(用双引号或单引号分隔)以及在非构造性上下文中(即未使用 `new` 关键字调用)从字符串调用返回的字符串都是原始字符串。在需要对原始字符串调用方法或进行属性查找的上下文中,JavaScript 会自动包装原始字符串,并对包装后的对象调用方法或执行属性查找。.
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原始字符串和字符串对象在使用 `eval()` 函数时会产生不同的结果。传递给 `eval` 的原始字符串会被视为源代码。而返回对象的字符串对象则会像其他对象一样被处理。例如:
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"因此,当代码遇到字符串对象而预期的是原始字符串时,可能会出错,但一般来说,作者无需担心这种区别。.
可以使用 valueOf() 方法将 String 对象转换为其原始对应对象。.
console.log(eval(s2.valueOf())); // returns the number 4
字符串强制转换
许多内置的、需要字符串参数的操作,都会先将参数强制转换为字符串(这就是为什么 String 对象的行为类似于原始字符串)。这些操作可以概括如下:
- 字符串将按原样返回。.
- 未定义变为“undefined”。.
- null 变为“空”。.
- True 变为“true”,False 变为“false”。.
- 数字的转换算法与 toString(10) 相同。.
- BigInt 的转换算法与 toString(10) 相同。.
- 符号会引发 TypeError。.
- 首先,通过分别调用 `[Symbol.toPrimitive]()`(提示参数为“string”)、`toString()` 和 `valueOf()` 方法,将对象转换为基本类型。然后,将转换后的基本类型转换为字符串。.
在 JavaScript 中,有多种方法可以实现大致相同的效果。.
- 字面上:`${x}` 执行与上面描述的嵌入式表达式完全相同的字符串绑定步骤。.
- String() 函数:String(x) 使用相同的算法转换 x,但 Symbols 不会引发 TypeError,而是返回“Symbol(description)”,其中 description 是符号的描述。.
- 使用 + 运算符:“” + x 会将其操作数强制转换为基本类型而非字符串,并且对于某些对象,其行为与常规字符串强制转换完全不同。有关更多详细信息,请参阅其参考页面。.
根据您的使用情况,您可能需要使用 `${x}`(以模仿内置行为)或 String(x)(以处理符号值而不会导致错误),但您不应该使用“” + x。 .
UTF-16 字符、Unicode 代码点和字形簇
字符串本质上是由一系列 UTF-16 编码单元表示的。在 UTF-16 编码中,每个编码单元的长度为 16 位。这意味着一个 UTF-16 编码单元最多可以包含 2^16 或 65,536 个字符。这种字符集被称为基本多语言页 (BMP),包含了最常用的字符,例如拉丁字母、希腊字母、西里尔字母以及许多东亚字符。每个编码单元都可以用 \u 符号后跟四个十六进制数字来表示。.
然而,整个 Unicode 字符集远大于 65536 个字符。UTF-16 中的额外字符以代理对的形式存储,代理对是由两个 16 位代码单元组成的,每个代码单元代表一个字符。为了避免歧义,代理对的两个部分必须介于 0xD800 和 0xDFFF 之间,并且这些代码单元不用于编码单个字符。(更准确地说,前导代理(也称为上代理代码单元)的值介于 0xD800 和 0xDBFF 之间,而尾随代理(也称为下代理代码单元)的值介于 0xDC00 和 0xDFFF 之间,包括 Unicode 字符。)由一个或两个 UTF-16 代码单元组成的字符也称为 Unicode 代码点。任何 Unicode 代码点都可以用 \u{xxxxxx} 表示,其中 xxxxxx 代表 1 到 6 个十六进制数字。.
“单个代理”是一个 16 位代码单元,它符合以下描述之一:
- 在 0xD800–0xDBFF 范围内(包括 0xD800–0xDBFF),但 0xD800–0xDBFF 是字符串中的最后一个代码单元,或者下一个代码单元不是最后一个代码单元。.
- 在 0xDC00–0xDFFF 范围内(包括 0xDC00–0xDFFF),即最后一个代理,但字符串中的第一个代码单元或前一个代码单元不是原始代理。.
单个代理项不代表任何 Unicode 字符。虽然大多数 JavaScript 内部方法都能正确处理它们(因为它们都基于 UTF-16 编码单元),但在与其他系统交互时,单个代理项通常不是有效值——例如,`encodeURI()` 函数会对单个代理项抛出 URIE 错误,因为 URI 编码使用 UTF-8 编码,而 UTF-8 编码不支持单个代理项。不包含任何单个代理项的字符串称为格式良好的字符串,可以安全地与不处理 UTF-16 编码的函数(例如 `encodeURI()` 或 `TextEncoder`)一起使用。您可以使用 `isWellFormed()` 方法检查字符串是否格式良好,或者使用 `toWellFormed()` 方法清除单个代理项。.
在 Unicode 字符之上,还有一串特定的 Unicode 字符,它们必须被视为一个视觉单元,称为图形簇。最常见的例子是表情符号:许多表情符号(种类繁多)实际上是由多个表情符号组合而成,通常包含字符“emoji”。 (U+200D)连接在一起。.
你需要谨慎选择迭代的字符层级。例如,`split(“”)` 会按 UTF-16 代码单元分割字符,并将交替的字符对分开。字符串索引也指向每个 UTF-16 代码单元的索引。另一方面,`[Symbol.iterator]()` 会按 Unicode 代码点进行迭代。遍历字形簇需要编写自定义代码。.
"😄".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.fromCharCode()
返回使用指定的 Unicode 值序列创建的字符串。.
String.fromCodePoint()
返回使用指定的代码点序列创建的字符串。.
String.raw()
返回由原始模式字符串创建的字符串。.
示例属性
这些属性在 String.prototype 中定义,并由所有 String 实例共享。.
String.prototype.constructor
创建实例对象的构造函数。对于字符串实例,初始值是字符串构造函数。.
这些特征是每个字符串实例特有的。.
长度
反映字符串的长度。只读。.
抽样方法
String.prototype.at()
返回指定索引处的字符(恰好一个 UTF-16 代码单元)。接受从字符串最后一个字符开始倒数的负整数。.
String.prototype.charAt()
返回指定索引中的字符(恰好一个 UTF-16 代码单元)。.
String.prototype.charCodeAt()
返回一个数字,该数字是给定索引处的 UTF-16 代码单元的值。.
String.prototype.codePointAt()
返回一个非负整数,该整数是指定姿态开始的 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()
返回所有正则表达式匹配项的迭代器。.
String.prototype.normalize()
Unicode规范化形式返回调用字符串的值。.
String.prototype.padEnd()
将当前字符串从末尾与一个字符串连接起来,并返回长度为 targetLength 的新字符串。.
String.prototype.padStart()
使用给定的字符串从当前字符串的开头填充该字符串,并返回长度为 targetLength 的新字符串。.
String.prototype.repeat()
返回一个字符串,该字符串由对象元素的次数组成。.
String.prototype.replace()
SearchFor 用于使用 replaceWith 替换项。searchFor 可以是字符串或正则表达式,replaceWith 可以是字符串或函数。.
String.prototype.replaceAll()
SearchFor 用于替换 replaceWith 的所有出现位置。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]()
返回一个新的迭代器对象,该对象遍历字符串值的代码点,并将每个代码点作为字符串值返回。.









