JavaScript字符串定义、转义与编码处理详解

作者:函数茶馆

时间:2026-10-30

浏览:292

本文详解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') // "你好"

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章