JS 字符串17个常用方法和属性总结

170 阅读7分钟

前言

初级程序员调 API,中级程序员封装,高级程序员造轮子。

—— Frank Fang 方方老师

常用方法

字符串的方法,全部定义在String.prototype上。

1. charAt()

传入一个索引值,返回值是索引值对应的单个字符

语法: str.charAt(index)

示例:

let str = 'Hi~ Jeffrey'
console.log(str.charAt(4)) // J

2. includes()

用于检查字符串中是否包含某一段字符串,会返回一个布尔值。

语法:

str.includes(searchString[, position])

参数说明:

  • searchString:搜索的字符串,不能是正则表达式。
  • position: 从哪个索引值开始搜索,默认为 0。

示例:

const str = 'Hello Jeffrey'
str.includes('Jeffrey') // true

3. match()

字符串调用这个方法后,若通过正则校验则会返回一个数组,数组中包含匹配项信息;若未通过则返回 null

语法: str.match(regexp)

参数说明:

  • regexp:可以是任何实现了Symbol.match方法的对象,比如正则表达式。

返回值:

取决于正则表达式是否有g标识(g flag)以及是否有匹配项。

  • 如果没有匹配项:返回 null
  • 如果有匹配项,返回数组。
    • 如果有 g flag,所有的匹配项都会返回,但不含捕获组信息。数组包含以下键值:
      • <number>:从 0 开始的数组索引,依次对应所有匹配项。
      • length:匹配项的数量。
    • 如果没有 g flag,只返回第一个匹配项,以及捕获组信息。数组包含以下键值:
      • 0:对应第一个匹配项
      • length:匹配项和捕获组的数量和。
      • index:匹配项的第一个字符在原字符串中的索引值
      • input:原始字符串
      • groups命名捕获组,而非普通捕获组。

正则表达式「捕获组」相关语法:

字符集含义
(x)捕获组 Capturing group
(?<Name>x)命名捕获组 Named capturing group
(?:x)非捕获组 Non-capturing group

示例:

// 1. 利用 ^ 与 $ 进行全字符串匹配,不要加 g flag
let name1 = 'I love sunshine', reg1 = /^[a-zA-Z\s]+$/
console.log(name1.match(reg1))
// ['I love sunshine', index: 0, input: 'I love sunshine', groups: undefined]

// 2. 匹配所有非连续的单词时,加 g flag
let name2 = 'I love sunshine love', reg2 = /love/g
console.log(name2.match(reg2)) // ['love', 'love']

// 3. 如果想用捕获组或命名捕获组,不要加 g flag
let name3 = 'I love sunshine', reg3 = /love (sunshine)/
console.log(name3.match(reg3))
// ['love sunshine', 'sunshine', index: 2, input: 'I love sunshine', groups: undefined]

let name4 = 'I love sunshine', reg4 = /love (?<key>sunshine)/
console.log(name4.match(reg4))
// ['love sunshine', 'sunshine', index: 2, input: 'I love sunshine', groups: { key: 'sunshine' }]

4. matchAll()

返回一个包含所有匹配正则表达式的结果及捕获组的迭代器,此方法是 str.match(regexp) 的“更新、改进”的变体。

match 相比有 4 个区别:

  1. 它返回一个包含匹配项的可迭代对象,而不是数组。我们可以用 Array.from() 将其转换为一个数组。如果用 for..of 来遍历可迭代对象,也可以不需要 Array.from()
  2. 正则参数 regexp 必须设置为全局模式(g flag)。
  3. 每个匹配项均以一个数组形式返回(返回格式与不带修饰符 g 的 str.match() 相同)。
  4. 如果没有结果,则返回的是一个空的可迭代对象而不是 null。(RegExpStringIterator {}

语法:

str.matchAll(regexp)

参数说明:

regexp 必须设置为全局模式(g flag),否则会抛出异常。

返回值:

一个迭代器(不可重用,结果耗尽需要再次调用方法,获取一个新的迭代器)。

示例:

let str = '<h1>Hello</h1>'
let regexp = /<(.*?)>/g // 捕获组
// 命名捕获组 /<(?<group1>.*?)>/g

let match1 = str.matchAll(regexp)

console.log(match1) // RegExpStringIterator {},不是数组,而是一个可迭代对象

for (let arr of match1) {
    console.log(arr)
    // ['<h1>', 'h1', index: 0, input: '<h1>Hello</h1>', groups: undefined]
    // ['</h1>', '/h1', index: 9, input: '<h1>Hello</h1>', groups: undefined]
}

5. replace()

可以把字符串中符合要求的字符修改为指定字符。

语法:

str.replace(regexp|substr, newSubStr|function)

示例:

let tel = '134 1234 1234'
console.log(tel.replace(/ /g,'-')) // 134-1234-1234

6. replaceAll()

可以把字符串中所有符合要求的字符替换为指定字符

示例:

let tel = '134 1234 1234'
console.log(tel.replaceAll(' ','-')) // 134-1234-1234

7. split()

分割字符串,括号内传入的字符表示要以什么字符分割,最终返回一个数组。

示例:

const str = "Hello World";
const target = str.split(' ');

console.log(target); // ["Hello", "World"];

8. substring()

截取字符串。传入两个参数,分别是截取的起始索引和终止索引(在该索引处结束提取字符串)。

语法:

str.substring(indexStart[, indexEnd])

参数说明:

  • 如果任一参数小于 0,则被当作 0。
  • 如果 indexStart 大于 indexEnd,则 substring 的执行效果就像两个参数调换了一样。

示例:

let anyString = "Mozilla";

// 输出 "Moz"
console.log(anyString.substring(0,3));
console.log(anyString.substring(3,0));
console.log(anyString.substring(3,-3)); // indexEnd 小于 0,被视作 0
console.log(anyString.substring(-2,3));

9. slice()

截取字符串。传入两个参数,分别是截取的起始索引和终止索引。产生一个新字符串,不修改原字符串。

语法:

str.slice(indexStart[, indexEnd])

参数说明:

  • 如果 indexEnd 小于 0,则终止索引就是倒数第 |indexEnd| 个。如果超出字符串长度,indexEnd 视为 0。

示例:

let anyString = "Mozilla"

// 输出 "Moz"
console.log(anyString.slice(0, 3))
console.log(anyString.slice(0, -4)) // 提取第 1 个字符到倒数第 4 个字符(不含倒数第 4 个)

10. substr()

截取字符串。不推荐使用此方法,以便软件最大程度地跨平台应用。用substring()slice()方法代替。如果有代码用了 substr() 看懂即可,先不要修改,等出了问题再修改。

it's defined in Annex B: Additional ECMAScript Features for Web Browsers, which is normative optional for non-browser runtimes.

语法:

str.substr(start[, length])

参数说明:

  • 如果 start 为负值,则 substr 把它作为从字符串末尾倒数第|start|个开始的一个字符索引。

示例:

let str = "abcdefghij";

console.log("(1,2): "  + str.substr(1,2));   // (1,2): bc
console.log("(-3,2): " + str.substr(-3,2));  // (-3,2): hi

11. toLowerCase() / toUppercase()

将字符串转变大小写

示例:

const username = 'Jeffrey'

console.log(username.toLowerCase()) // jeffrey
console.log(username.toUpperCase()) // JEFFREY

12. trim()

去除字符串左右两端的空白字符,对字符串中间的空格无效

示例:

const username = '  ca t  '

console.log(username.trim()) // ca t

13. indexOf()

找到指定字符串首次出现时,第一个字符的索引值

示例:

const str = 'Hi, dude~ Nice to meet you, dude~'
console.log(str.indexOf('dude')) // 4

14. lastIndexOf()

找到指定字符串最后一次出现时,第一个字符的索引值

const str = 'Hi, dude~ Nice to meet you, dude~'
console.log(str.lastIndexOf('dude')) // 28

15. search()

找到指定正则表达式首次匹配时的索引。没有匹配项则返回 -1。

参数说明: 如果传入字符串,会自动通过new Regexp(obj)语法转换为正则表达式。

语法:

str.search(regexp)

示例:

const str = "hey Jude";
const re = /[A-Z]/
str.search(re) // 4

16. charCodeAt()

返回一个 0 ~ 65536 范围间的十进制数,这个数字代表 UTF-16 字符给定索引的码点。

示例:

// 先把字符串转为 UTF-16 编码格式
const emoji = "😄"; // "\uD83D\uDE04"
emoji.charCodeAt(0) // 55357 '\uD83D'
emoji.charCodeAt(1) // 56836 '\uDE04'

17. codePointAt()

返回一个十进制数,这个数字代表 UTF-16 字符给定索引的码点(code point)。

当字符串之间存在代理对(surrogate pair),它与charCodeAt()就有区别了。

  • 如果码点位置是代理对的高位(UTF-16 high surrogate),则返回整个代理对的码点;
  • 如果码点位置是代理对的低位(UTF-16 low surrogate),则只返回低位的码点。

示例:

// 先把字符串转为 UTF-16 编码格式
const emoji = "😄"; // "\uD83D\uDE04"
emoji.codePointAt(0) // 128516 '\u{1F604}'
emoji.codePointAt(1) // 56836 '\uDE04'

常用属性

字符串的属性,实际上是包装之后的 String 对象才有。执行完,包装对象自动销毁。

1. length

返回字符串的 UTF-16 编码格式的代码单元(code units)的长度。

const emoji1 = "😄" // "\uD83D\uDE04"
console.log(emoji1.length) // 2
const emoji2 = "👩‍🦱" // "\uD83D\uDC69\u200D\uD83E\uDDB1"
console.log(emoji2.length) // 5

如果想获取字符串中的字符数,而不是 UTF-16 代码单元长度,用扩展运算符。这种情况下每个代理对(surrogate pair)将会被视作一个字符。

const emoji1 = "😄" // "\uD83D\uDE04"
console.log([...emoji1].length) // 1
const emoji2 = "👩‍🦱" // "\uD83D\uDC69\u200D\uD83E\uDDB1"
console.log([...emoji2].length) // 3,相当于 "👩\u200D🦱"

遍历字符串

1. 遍历每个字符

同样地,每个代理对将会被视作一个字符。

// 可以通过 break, continue 等语法提前结束循环
for(const char of 'A😄C'){
    console.log(char) // A, 😄, C
}

或者

// 无法提前退出循环
[...'A😄C'].forEach((char, i)=>{console.log(char)}) // A, 😄, C

2. 遍历每个 UTF-16 代码单元

let str = '😄'
for (let i = 0; i < str.length; i++) {
    console.log(`"\\u${str.charCodeAt(i).toString(16)}"`)
    // "\ud83d"
    // "\ude04"
}