JavaScript字符串定义、转义与编码处理详解
本文详解JavaScript中字符串的定义与书写规范,包括单双引号的使用及多行字符串的多种实现方式。深入解析反斜杠转义符的特殊用法、不可变性以及length属性。重点探讨UTF-16编码下4字节字符(辅助平面)的处理难点,并提供正确的遍历与编码转换方案。
JavaScript字符串定义与书写规范
字符串由零个或多个连续字符组成,书写时需包裹在单引号或双引号内。
'abc'
"abc"
在单引号包裹的字符串内部可以直接使用双引号,反之,在双引号字符串内部也可使用单引号。
'key = "value"'
"It's a long journey"
上述两种写法均符合JavaScript语法规范。
若需在单引号字符串内使用单引号,或在双引号字符串内使用双引号,必须在前置的反斜杠进行转义处理。
'Did she say \'Hello\'?'
// "Did she say 'Hello'?"
"Did she say \"Hello\"?"
// "Did she say "Hello"?"
鉴于HTML属性值通常采用双引号,许多JavaScript项目约定字符串统一使用单引号,本教程亦遵循此规范。当然,统一使用双引号亦可,关键在于保持风格一致,避免混用。
默认情况下,字符串必须书写在一行内,强行分行会导致语法错误。
'a
b
c'
// SyntaxError: Unexpected token ILLEGAL
上述代码尝试将字符串分为三行,JavaScript引擎会抛出错误。
若长字符串必须分行书写,可在每一行的末尾添加反斜杠。
var longString = "Long \
long \
long \
string";
longString
// "Long long long string"
添加反斜杠后,原本单行的字符串可分行书写,但输出结果仍为单行,效果等同于写在同一行。需注意,反斜杠后必须紧跟换行符,若存在空格等其他字符,将导致报错。
利用连接运算符(+)可将多个单行字符串拼接,实现长字符串的多行书写,输出时同样为单行。
var longString = 'Long '
+ 'long '
+ 'long '
+ 'string';
若需输出多行字符串,可利用多行注释特性进行变通处理。
(function () { /*
line 1
line 2
line 3
*/}).toString().split('\n').slice(1, -1).join('\n')
// "line 1
// line 2
// line 3"
上述示例中,通过该方式输出的字符串即为多行格式。
字符串转义与特殊字符处理
转义 反斜杠(\)在字符串中具有特殊含义,用于表示特定字符,因此被称为转义符。
需要使用反斜杠进行转义的特殊字符主要包括以下类别:
- \0 空字符(\u0000)
- \b 退格键(\u0008)
- \f 换页符(\u000C)
- \n 换行符(\u000A)
- \r 回车键(\u000D)
- \t 制表符(\u0009)
- \v 垂直制表符(\u000B)
- \' 单引号(\u0027)
- \" 双引号(\u0022)
- \\ 反斜杠(\u005C)
在上述字符前添加反斜杠,即表示其特殊含义。
console.log('1\n2')
// 1
// 2
上述代码中,\n代表换行,输出时字符串将分为两行显示。
反斜杠还有三种特殊的编码用法。
(1)\HHH
反斜杠后紧跟三个八进制数(范围000至377),代表一个字符。HHH对应字符的Unicode码点,例如\251表示版权符号。此方法仅能表示256种字符。
(2)\xHH
\x后紧跟两个十六进制数(范围00至FF),代表一个字符。HH对应字符的Unicode码点,例如\xA9表示版权符号。此方法同样仅能表示256种字符。
(3)\uXXXX
\u后紧跟四个十六进制数(范围0000至FFFF),代表一个字符。HHHH对应字符的Unicode码点,例如\u00A9表示版权符号。
以下是这三种特殊字符写法的示例。
'\251' // "©"
'\xA9' // "©"
'\u00A9' // "©"
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true
若在非特殊字符前使用反斜杠,该反斜杠将被自动忽略。
'\a'
// "a"
上述代码中,a为普通字符,前加反斜杠无特殊含义,反斜杠会被自动省略。
若字符串内容中需包含反斜杠本身,则需在反斜杠前再加一个反斜杠以进行自身转义。
"Prev \\ Next"
// "Prev \ Next"
字符串与数组的异同及长度属性
字符串与数组 字符串可视为字符数组,因此可使用数组的方括号运算符获取指定位置的字符(索引从0开始)。
var s = 'hello';
s[0] // "h"
s[1] // "e"
s[4] // "o"
// 直接对字符串使用方括号运算符
'hello'[1] // "e"
若方括号内的数字超出字符串长度,或非数字类型,则返回undefined。
'abc'[3] // undefined
'abc'[-1] // undefined
'abc'['x'] // undefined
然而,字符串与数组的相似性仅止于此。实际上,无法修改字符串中的单个字符。
var s = 'hello';
delete s[0];
s // "hello"
s[1] = 'a';
s // "hello"
s[5] = '!';
s // "hello"
上述代码表明,字符串内部的单个字符无法被修改或增删,相关操作会静默失败。
字符串之所以类似数组,是因为对方括号运算时,字符串会自动转换为字符串对象。
length属性 length属性返回字符串长度,该属性值不可更改。
var s = 'hello';
s.length // 5
s.length = 3;
s.length // 5
s.length = 7;
s.length // 5
上述代码显示,字符串的length属性无法被修改,但不会抛出错误。
Unicode编码与UTF-16处理机制
字符集 JavaScript采用Unicode字符集,即内部所有字符均以Unicode形式表示。
不仅JavaScript内部使用Unicode存储字符,程序中也可直接使用Unicode,所有字符均可写作“\uxxxx”形式,其中xxxx代表该字符的Unicode编码。例如,\u00A9代表版权符号。
var s = '\u00A9';
s // "©"
每个字符在JavaScript内部均以16位(即2字节)的UTF-16格式存储。这意味着JavaScript的单位字符长度固定为16位,即2字节。
然而,UTF-16存在两种长度:对于U+0000至U+FFFF之间的字符,长度为16位(2字节);对于U+10000至U+10FFFF之间的字符,长度为32位(4字节),且前两个字节位于0xD800至0xDBFF之间,后两个字节位于0xDC00至0xDFFF之间。例如,U+1D306对应的字符为𝌆,其UTF-16编码为0xD834 0xDF06。浏览器能正确识别这四个字节为一个字符,但JavaScript内部字符长度固定为16位,会将这四个字节视为两个字符。
var s = '\uD834\uDF06';
s // "𝌆"
s.length // 2
/^.$/.test(s) // false
s.charAt(0) // ""
s.charAt(1) // ""
s.charCodeAt(0) // 55348
s.charCodeAt(1) // 57094
上述代码说明,对于U+10000至U+10FFFF之间的字符,JavaScript始终视为两个字符(length属性值为2),用于匹配单个字符的正则表达式将失败(JavaScript认为此处不止一个字符),charAt方法无法返回单个字符,charCodeAt方法返回每个字节对应的十进制值。
因此处理时需考虑此因素。对于4字节的Unicode字符,假设C为字符的Unicode编号,H为前两个字节,L为后两个字节,其换算关系如下。
// 将大于U+FFFF的字符,从Unicode转为UTF-16
H = Math.floor((C - 0x10000) / 0x400) + 0xD800
L = (C - 0x10000) % 0x400 + 0xDC00
// 将大于U+FFFF的字符,从UTF-16转为Unicode
C = (H - 0xD800) * 0x400 + L - 0xDC00 + 0x10000
以下正则表达式可识别所有UTF-16字符。
([\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF])
由于JavaScript引擎(严格而言是ES5规范)无法自动识别辅助平面(编号大于0xFFFF)的Unicode字符,导致所有字符串处理函数遇到此类字符时均产生错误结果。若要完成字符串相关操作,必须判断字符是否落在0xD800至0xDFFF区间内。
以下是能正确处理字符串遍历的函数。
function getSymbols(string) {
var length = string.length;
var index = -1;
var output = [];
var character;
var charCode;
while (++index < length) {
character = string.charAt(index);
charCode = character.charCodeAt(0);
if (charCode >= 0xD800 && charCode <= 0xDBFF) {
output.push(character + string.charAt(++index));
} else {
output.push(character);
}
}
return output;
}
var symbols = getSymbols('𝌆');
symbols.forEach(function(symbol) {
// ...
});
替换(String.prototype.replace)、截取子字符串(String.prototype.substring, String.prototype.slice)等其他字符串操作,均需进行类似处理。
Base64编码转换方法
Base64转码 Base64是一种编码方法,可将任意字符转换为可打印字符。使用这种编码方法,主要目的并非加密,而是避免特殊字符,简化程序处理。
JavaScript原生提供两个Base64相关方法。
- btoa():将字符串或二进制值转换为Base64编码
- atob():将Base64编码转换回原始编码
var string = 'Hello World!';
btoa(string) // "SGVsbG8gV29ybGQh"
atob('SGVsbG8gV29ybGQh') // "Hello World!"
这两个方法不适合非ASCII码的字符,会报错。
btoa('你好')
// Uncaught DOMException: The string to be encoded contains characters outside of the Latin1 range.
要将非ASCII码字符转为Base64编码,必须中间插入一个转码环节,再使用这两个方法。
function b64Encode(str) {
return btoa(encodeURIComponent(str));
}
function b64Decode(str) {
return decodeURIComponent(atob(str));
}
b64Encode('你好') // "JUU0JUJEJUEwJUU1JUE1JUJE"
b64Decode('JUU0JUJEJUEwJUU1JUE1JUJE') // "你好"
JS大数值转字符串出现科学计数法怎么办
2026-11-05 17:09:21
JS split切割后出现空字符串怎么过滤
2026-11-05 16:00:30
在 React 或 Vue 项目中封装使用 JS 节流防抖
2026-11-05 15:27:29
JavaScript中怎么将带小数的字符串转为整数?
2026-11-05 14:32:38
怎么用JavaScript策略模式重构电商促销计算逻辑?
2026-11-05 14:01:09
