JavaScript字符串为原始类型且不可变,方法调用时自动包装;length返回UTF-16编码单元数,非用户感知字符数,代理对(如emoji)会返回2;应使用[...str].length或Array.from(str).length获取真实字符数。

JavaScript字符串是原始类型,但能直接调用方法(引擎自动包装为String对象),所有操作均不修改原字符串(字符串不可变)。
length属性:获取真实字符数(注意Unicode代理对)
length返回UTF-16编码单元个数,非用户感知的“字符数”。遇到emoji或部分中文生僻字(如U+1F926♂️、?)可能返回2,因它们由两个16位码元组成(代理对)。
- 普通英文、数字、ASCII汉字:length = 字符数
- 含emoji或扩展Unicode字符时,建议用
[...str].length或Array.from(str).length获取实际字符数 - 避免用
str.length做截断逻辑的唯一依据,否则可能切在代理对中间,产生
charAt() 与 charCodeAt():安全访问单个码元
两者都按UTF-16索引操作,索引超出范围时返回空字符串或NaN,不会报错。
-
str.charAt(0)返回索引处的单字符字符串(始终是长度为1的字符串) -
str.charCodeAt(0)返回该位置UTF-16码元值(0–65535),对代理对高位返回高代理项,低位返回低代理项 - 需获取完整Unicode字符码点时,应使用
str.codePointAt(0)(支持代理对,返回正确码点如0x1F926)
substring()、slice()、substr():三者截取逻辑差异明显
它们都不修改原串,返回新字符串;但参数处理和负数行为不同,易混淆。
立即学习“Java免费学习笔记(深入)”;
-
substring(start, end):自动交换大小顺序(substring(3,1) === substring(1,3)),负数转0 -
slice(start, end):支持负数(从末尾计数,slice(-3)取后3个),不交换顺序,越界静默处理 -
substr(start, length):第二个参数是**长度**而非结束索引;已废弃,不应在新代码中使用
includes()、startsWith()、endsWith():区分大小写且支持起始位置
三者均为ES6新增,返回布尔值,语法简洁,但默认区分大小写,且都支持第三个可选参数(仅对startsWith和endsWith有效,指定搜索起始/结束位置)。
-
"Hello".includes("ll") → true;"Hello".includes("LL") → false -
"Hello".startsWith("He", 1) → false(从索引1开始检查,实际检查的是"ello"是否以"He"开头) -
"Hello".endsWith("lo", 4) → true(只检查前4个字符"Hell"是否以"lo"结尾) - 如需忽略大小写,先转同一种大小写:
str.toLowerCase().includes(search.toLowerCase())
replace() 与 replaceAll():正则与全局替换的关键区别
replace() 默认只替换第一个匹配项;若传入字符串目标,永远只换一次;若传入正则且无g标志,也只换第一个。
"aabbcc".replace("b", "_") → "aa_bcc""aabbcc".replace(/b/g, "_") → "aa__cc"-
"aabbcc".replaceAll("b", "_") → "aa__cc"(ES2021新增,字符串目标即全局替换,无需正则) - 注意:
replaceAll()对字符串目标要求严格相等,不支持正则标志(如i),如需忽略大小写全局替换,仍须用replace(/b/gi, "_")
split():分隔符为空字符串时的特殊行为
str.split("") 将字符串拆为单字符数组,但同样受UTF-16限制——代理对会被拆成两个元素。
-
"??".split("") → ["", ""](错误拆分) - 安全做法:
[...str]或Array.from(str),它们按Unicode字符分割,正确处理代理对和组合字符 -
split(separator, limit)的limit参数控制结果数组最大长度,超出部分被丢弃
字符串操作看似简单,但Unicode、不可变性、方法边界行为这些细节稍不注意就会引发隐性bug。掌握各方法的“默认假设”和“失效场景”,比记住语法更重要。










