字符串常用方法

字符串对象是不可变的,所以字符串对象提供的涉及到字符串“修改”的方法都是返回修改后的新字符串,并不对原始字符串做任何修改,无一例外
JavaScript字符串由 16位码元(code unit)组成。对多数字符来说,每 16位码元对应一个字符。
JavaScript字符串使用了两种 Unicode编码混合的策略:UCS-2和 UTF-16。对于可以采用 16位编码 的字符(U+0000~U+FFFF)16的四次方

charAt()

charAt()方法返回给定索引位置的字符,由传给方法的整数参数指定。具体来说,这个方法查找指定索引位置的 16位码元,并返回该码元对应的字符:

1
2
3
let message = "abcde"; 

console.log(message.charAt(2)); // "c"

charCodeAt()

使用 charCodeAt()方法可以查看指定码元的字符编码。这个方法返回指定索引位置的码元值,索引以整数指定

1
2
3
let message = "abcde"; 
// Unicode "Latin small letter C"的编码是 U+0063
console.log(message.charCodeAt(2)); // 99

fromCharCode() 原型方法

fromCharCode() 方法用于根据给定的 UTF-16 码元创建字符串中的字符。这个方法可以接受任意多个数值,并返回将所有数值对应的字符拼接起来的字符串:

1
console.log(String.fromCharCode(0x61, 0x62, 0x63, 0x64, 0x65));  // "abcde"

对于 U+0000~U+FFFF范围内的字符,length、charAt()、charCodeAt()和 fromCharCode() 返回的结果都跟预期是一样的。
为正确解析既包含单码元字符又包含代理对字符的字符串,与charCodeAt()有对应的 codePointAt()一样,fromCharCode()也有一个对应的 fromCodePoint()

normalize() 非诚不常用

,Unicode提供了4种规范化形式,可以将类似上面的字符规范化为一致的格式,无论 底层字符的代码是什么。这 4种规范化形式是:NFD(Normalization Form D)、NFC(Normalization Form C)、 NFKD(Normalization Form KD)和 NFKC(Normalization Form KC)。可以使用 normalize()方法对字 符串应用上述规范化形式,使用时需要传入表示哪种形式的字符串:”NFD”、”NFC”、”NFKD”或”NFKC”。

concat()

首先是 concat(),用于将一个或多个字符串拼接成一个新字符串。concat()方法可以接收任意多个参数,因此可以一次性拼接多个字符串。

1
2
3
4
let stringValue = "hello "; 
let result = stringValue.concat("world", "!");
console.log(result); // "hello world!"
console.log(stringValue); // "hello "

虽然 concat()方法可以拼接字符串,但更常用的方式是使用加号操作符(+)。而且多数情况下,对于拼接多个字符串来说,使用加号更方便。

slice()、substr() 和 substring() 截取字符串

这3个方法都返回调用它们的字符串的一个子字符串,而且都接收一或两个参数。第一个参数表示子字符串开始的位置,第二个参数表示子字符串结束的位置。
slice()substring()而言,第二个参数是提取结束的位置(即该位置之前的字符会被提取出来)。
substr()而言,第二个参数表示返回的子字符串数量。任何情况下,省略第二个参数都意味着提取到字符串末尾。

1
2
3
4
5
6
7
let stringValue = "hello world"; 
console.log(stringValue.slice(3)); // "lo world"
console.log(stringValue.substring(3)); // "lo world"
console.log(stringValue.substr(3)); // "lo world"
console.log(stringValue.slice(3, 7)); // "lo w"
console.log(stringValue.substring(3,7)); // "lo w"
console.log(stringValue.substr(3, 7)); // "lo worl"

当某个参数是负值时,这3个方法的行为又有不同。
比如,slice()方法将所有负值参数都当成字符串长度加上负参数值。
而substr()方法将第一个负参数值当成字符串长度加上该值,将第二个负参数值转换为 0。
substring()方法会将所有负参数值都转换为 0。

1
2
3
4
5
6
7
let stringValue = "hello world"; 
console.log(stringValue.slice(-3)); // "rld"
console.log(stringValue.substring(-3)); // "hello world"
console.log(stringValue.substr(-3)); // "rld"
console.log(stringValue.slice(3, -4)); // "lo w"
console.log(stringValue.substring(3, -4)); // "hel"
console.log(stringValue.substr(3, -4)); // "" (empty string)

indexOf() 和 lastIndexOf() 字符串位置方法

这两个方法从字符串中搜索传入的字符串,并返回位置(如果没找到,则返回-1)。两者的区别在于,indexOf()方法 从字符串开头开始查找子字符串,而 lastIndexOf()方法从字符串末尾开始查找子字符串

1
2
3
let stringValue = "hello world"; 
console.log(stringValue.indexOf("o")); // 4
console.log(stringValue.lastIndexOf("o")); // 7

这两个方法都可以接收可选的第二个参数,表示开始搜索的位置。这意味着,indexOf()会从这个参数指定的位置开始向字符串末尾搜索,忽略该位置之前的字符;lastIndexOf()则会从这个参数指定的位置开始向字符串开头搜索,忽略该位置之后直到字符串末尾的字符。

1
2
3
let stringValue = "hello world"; 
console.log(stringValue.indexOf("o", 6)); // 7
console.log(stringValue.lastIndexOf("o", 6)); // 4

startsWith()、endsWith() 和 includes() 字符串包含方法

这些方法都会从字符串中搜索传入的字符串,并返回一个表示是否包含的布尔值。它们的区别在于,startsWith()检查开始于索引 0 的匹配项,endsWith()检查开始于索引(string.length - substring.length)的匹配项,而 includes()检查整个字符串

1
2
3
4
5
6
7
let message = "foobarbaz"; 
console.log(message.startsWith("foo")); // true
console.log(message.startsWith("bar")); // false
console.log(message.endsWith("baz")); // true
console.log(message.endsWith("bar")); // false
console.log(message.includes("bar")); // true
console.log(message.includes("qux")); // false

startsWith()和 includes()方法接收可选的第二个参数,表示开始搜索的位置

1
2
3
4
5
6
7
let message = "foobarbaz"; 

console.log(message.startsWith("foo")); // true
console.log(message.startsWith("foo", 1)); // false

console.log(message.includes("bar")); // true
console.log(message.includes("bar", 4)); // false

endsWith()方法接收可选的第二个参数,表示应该当作字符串末尾的位置

1
2
3
4
let message = "foobarbaz"; 

console.log(message.endsWith("bar")); // false
console.log(message.endsWith("bar", 6)); // true

trim()、 trimLeft() 和 trimRight()

trim()这个方法会创建字符串的一个副本,删除前、 后所有空格符,再返回结果

1
2
3
4
let stringValue = "  hello world  "; 
let trimmedStringValue = stringValue.trim();
console.log(stringValue); // " hello world "
console.log(trimmedStringValue); // "hello world"

trimLeft()和 trimRight()方法分别用于从字符串开始和末尾清理空格符。

repeat()

这个方法接收一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果

1
2
3
let stringValue = "na "; 
console.log(stringValue.repeat(16) + "batman");
// na na na na na na na na na na na na na na na na batman

padStart()和 padEnd()

padStart()padEnd()方法会复制字符串,如果小于指定长度,则在相应一边填充字符,直至满足长度条件。这两个方法的第一个参数是长度,第二个参数是可选的填充字符串,默认为空格(U+0020)

1
2
3
4
5
6
7
let stringValue = "foo"; 

console.log(stringValue.padStart(6)); // " foo"
console.log(stringValue.padStart(9, ".")); // "......foo"

console.log(stringValue.padEnd(6)); // "foo "
console.log(stringValue.padEnd(9, ".")); // "foo......"

可选的第二个参数并不限于一个字符。如果提供了多个字符的字符串,则会将其拼接并截断以匹配指定长度。此外,如果长度小于或等于字符串长度,则会返回原始字符串

1
2
3
4
5
6
7
let stringValue = "foo"; 

console.log(stringValue.padStart(8, "bar")); // "barbafoo"
console.log(stringValue.padStart(2)); // "foo"

console.log(stringValue.padEnd(8, "bar")); // "foobarba"
console.log(stringValue.padEnd(2)); // "foo"

toLowerCase()、toLocaleLowerCase()、toUpperCase() 和 toLocaleUpperCase() 大小写转换

toLowerCase()和toUpperCase()方法是原来就有的方法, 与 java.lang.String 中的方法同名。toLocaleLowerCase()和 toLocaleUpperCase()方法旨在基于特定地区实现

1
2
3
4
5
let stringValue = "hello world"; 
console.log(stringValue.toLocaleUpperCase()); // "HELLO WORLD"
console.log(stringValue.toUpperCase()); // "HELLO WORLD"
console.log(stringValue.toLocaleLowerCase()); // "hello world"
console.log(stringValue.toLowerCase()); // "hello world"

match() search() 和 replace() 字符串模式匹配方法

match()方法本质上跟 RegExp 对象的exec()方法相同。match()方法接收一个参数,可以是一个正则表达式字 符串,也可以是一个 RegExp 对象

1
2
3
4
5
6
7
8
let text = "cat, bat, sat, fat"; 
let pattern = /.at/;

// 等价于 pattern.exec(text)
let matches = text.match(pattern);
console.log(matches.index); // 0
console.log(matches[0]); // "cat"
console.log(pattern.lastIndex); // 0

search()这个方法返回模式第一个匹配的位置索引,如果没找到则返回-1。search()始终从字符串开头向后匹配模式

1
2
3
let text = "cat, bat, sat, fat"; 
let pos = text.search(/at/);
console.log(pos); // 1

replace()方法。这个方法接收两个参数,第一个参数可以是一个 RegExp 对象或一个字符串(这个字符串不会转换为正则表达式),第二个参数可以是一个字符串或一个函数。
如果第一个参数是字符串,那么只会替换第一个子字符串。要想替换所有子字符串,第一个参数必须为正则表达式并且带全局标记

1
2
3
4
5
6
let text = "cat, bat, sat, fat"; 
let result = text.replace("at", "ond");
console.log(result); // "cond, bat, sat, fat"

result = text.replace(/at/g, "ond");
console.log(result); // "cond, bond, sond, fond"

localeCompare()

这个方法比较两个字符串,返回如下 3个值中的一个。

  • 如果按照字母表顺序,字符串应该排在字符串参数前头,则返回负值。(通常是-1,具体还要看与实际值相关的实现。) 
  • 如果字符串与字符串参数相等,则返回 0。 
  • 如果按照字母表顺序,字符串应该排在字符串参数后头,则返回正值。(通常是 1,具体还要看与实际值相关的实现。)
stringValue
1
2
3
console.log(stringValue.localeCompare("brick"));  // 1 
console.log(stringValue.localeCompare("yellow")); // 0
console.log(stringValue.localeCompare("zoo")); // -1

matchAll()

matchAll()方法返回一个正则表达式在当前字符串的所有匹配,详见ES6深入浅出《正则的扩展》的一章。

replaceAll()

历史上,字符串的实例方法replace()只能替换第一个匹配。

1
2
'aabbcc'.replace('b', '_')
// 'aa_bcc'

上面例子中,replace()只将第一个b替换成了下划线。

如果要替换所有的匹配,不得不使用正则表达式的g修饰符。

1
2
'aabbcc'.replace(/b/g, '_')
// 'aa__cc'

正则表达式毕竟不是那么方便和直观,ES2021 引入了replaceAll()方法,可以一次性替换所有匹配。

1
2
'aabbcc'.replaceAll('b', '_')
// 'aa__cc'

它的用法与replace()相同,返回一个新字符串,不会改变原字符串。

更多详细用法见ES6深入浅出 string 方法章节