文章目录
一、原始值包装类型:String
String 是对应字符串的引用类型。要创建一个 String 对象,使用 String 构造函数并传入一个数值
let stringObject = new String("hello world");
- String 对象的方法可以在所有字符串原始值上调用
- 3个继承的方法 valueOf()、toLocaleString() 和 toString() 都返回对象的原始字符串值
每个 String 对象都有一个 length 属性,表示字符串中字符的数量
let stringValue = "hello world";
console.log(stringValue.length); // 11
注意,即使字符串中包含双字节字符(而不是单字节的 ASCII 字符),也仍然会按单字符来计数。
二、String 类型解析和操作字符串的方法
2.1 JavaScript 字符
JavaScript 字符串由 16 位码元(code unit)组成。对多数字符来说,每 16 位码元对应一个字符。换句话说,字符串的 length 属性表示字符串包含多少 16 位码元。
let message = "abcde";
console.log(message.length); // 5
JavaScript 字符串使用了两种 Unicode 编码混合的策略:UCS-2 和 UTF-16。对于可以采用16 位编码的字符(U+0000~U+FFFF),这两种编码实际上是一样的。
2.1.1 charAt()
charAt() 方法返回给定索引位置的字符,由传给方法的整数参数指定
- 这个方法查找指定索引位置的 16 位码元,并返回该码元对应的字符
let message = "abcde";
console.log(message.charAt(2)); // "c"
2.1.2 charCodeAt()
使用 charCodeAt() 方法可以查看指定码元的字符编码
- 这个方法返回指定索引位置的码元值,索引以整数指定
let message = "abcde";
// Unicode "Latin small letter C"的编码是 U+0063
console.log(message.charCodeAt(2)); // 99
// 十进制 99 等于十六进制 63
console.log(99 === 0x63); // true
2.1.3 fromCharCode()
fromCharCode()方法用于根据给定的 UTF-16 码元创建字符串中的字符
- 这个方法可以接受任意多个数值,并返回将所有数值对应的字符拼接起来的字符串
// Unicode "Latin small letter A"的编码是 U+0061
// Unicode "Latin small letter B"的编码是 U+0062
// Unicode "Latin small letter C"的编码是 U+0063
// Unicode "Latin small letter D"的编码是 U+0064
// Unicode "Latin small letter E"的编码是 U+0065
console.log(String.fromCharCode(0x61, 0x62, 0x63, 0x64, 0x65)); // "abcde"
// 0x0061 === 97
// 0x0062 === 98
// 0x0063 === 99
// 0x0064 === 100
// 0x0065 === 101
console.log(String.fromCharCode(97, 98, 99, 100, 101)); // "abcde"
2.2 字符串操作方法
2.2.1 拼接字符串 concat()
用于将一个或多个字符串拼接成一个新字符串
let stringValue = "hello ";
let result = stringValue.concat("world");
console.log(result); // "hello world"
console.log(stringValue); // "hello"
- concat()方法可以接收任意多个参数,因此可以一次性拼接多个字符串
- 但更常用的方式是使用加号操作符(+)
- 不会修改调用它们的字符串,只会返回原始新字符串值
let stringValue = "hello ";
let result = stringValue.concat("world", "!");
console.log(result); // "hello world!"
console.log(stringValue); // "hello"
2.2.2 从字符串中提取子字符串 slice()、substr()、 substring()
ECMAScript 提供了 3 个从字符串中提取子字符串的方法:slice()、substr()和 substring()。这3个方法都返回调用它们的字符串的一个子字符串,而且都接收一或两个参数。第一个参数表示子字符串开始的位置,第二个参数表示子字符串结束的位置
- 三者都不会修改调用它们的字符串,而只会返回提取到的原始新字符串值
方法 | 说明 |
---|---|
slice(star, end) | 从 star 位置开始,截取到 end位置,end取不到(都是索引),会将所有负值参数都当成字符串长度加上负参数值 |
substr(star, length) | 从 star 位置开始(索引号),length 取的个数,会将第一个负参数值当成字符串长度加上该值,将第二个负参数值转换为 0 |
substring(star, end) | 从 star 位置开始,截取到 end位置,end取不到,会将所有的负参数值都会转换为0 |
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"
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)
2.3 字符串位置方法 indexOf()、lastIndexOf()
有两个方法用于在字符串中定位子字符串:indexOf() 和 lastIndexOf()
- 这两个方法从字符串中搜索传入的字符串,并返回位置(如果没找到,则返回-1)
区别:
- indexOf() 方法从字符串开头开始查找子字符串
- lastIndexOf() 方法从字符串末尾开始查找子字符串
let stringValue = "hello world";
console.log(stringValue.indexOf("o")); // 4
console.log(stringValue.lastIndexOf("o")); // 7
//如果字符串中只有一个"o",则 indexOf()和 lastIndexOf()返回同一个位置
这两个方法都可以接收可选的第二个参数,表示开始搜索的位置
let stringValue = "hello world";
console.log(stringValue.indexOf("o", 6)); // 7
console.log(stringValue.lastIndexOf("o", 6)); // 4
示例:
let stringValue = "Lorem ipsum dolor sit amet, consectetur adipisicing elit";
let positions = [];
let pos = stringValue.indexOf("e");
while (pos > -1) {
positions.push(pos);
pos = stringValue.indexOf("e", pos + 1);
}
console.log(positions); // [3,24,32,35,52]
2.4 字符串包含方法-ES6新增 startsWith()、endsWith()、 includes()
ECMAScript 6 增加了 3 个用于判断字符串中是否包含另一个字符串的方法:startsWith()、endsWith()和 includes(),都会返回一个表示是否包含的布尔值
区别:
- startsWith() 检查开始于索引 0 的匹配项
- endsWith() 检查开始于索引( string.length - substring.length )的匹配项
- includes() 检查整个字符串
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() 方法接收可选的第二个参数,表示开始搜索的位置
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() 方法接收可选的第二个参数,表示应该当作字符串末尾的位置。如果不提供这个参数,那么默认就是字符串长度。如果提供这个参数,那么就好像字符串只有那么多字符一样:
let message = "foobarbaz";
console.log(message.endsWith("bar")); // false
console.log(message.endsWith("bar", 6)); // true
2.5 trim() 方法
ECMAScript 在所有字符串上都提供了 trim() 方法。这个方法会创建字符串的一个副本,删除前、后所有空格符,再返回结果
let stringValue = " hello world ";
let trimmedStringValue = stringValue.trim();
console.log(stringValue); // " hello world "
console.log(trimmedStringValue); // "hello world"
- trim() 返回的是字符串的副本,因此原始字符串不受影响,即原本的前、后空格符都会保留
- trimLeft() 和 trimRight() 方法分别用于从字符串开始和末尾清理空格符
2.6 repeat() 方法
ECMAScript 在所有字符串上都提供了 repeat() 方法。这个方法接收一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果。
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
2.7 padStart() 和 padEnd() 方法
padStart() 和 padEnd()方法会复制字符串,如果小于指定长度,则在相应一边填充字符,直至满足长度条件
- 这两个方法的第一个参数是长度,第二个参数是可选的填充字符串,默认为空格(U+0020)。
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......"
可选的第二个参数并不限于一个字符。如果提供了多个字符的字符串,则会将其拼接并截断以匹配指定长度。此外,如果长度小于或等于字符串长度,则会返回原始字符串。
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"
2.8 字符串迭代与解构
字符串的原型上暴露了一个 @@iterator 方法,表示可以迭代字符串的每个字符
let message = "abc";
let stringIterator = message[Symbol.iterator]();
console.log(stringIterator.next()); // {value: "a", done: false}
console.log(stringIterator.next()); // {value: "b", done: false}
console.log(stringIterator.next()); // {value: "c", done: false}
console.log(stringIterator.next()); // {value: undefined, done: true}
在 for-of 循环中可以通过这个迭代器按序访问每个字符
for (const c of "abcde") {
console.log(c);
}
// a
// b
// c
// d
// e
有了这个迭代器之后,字符串就可以通过解构操作符来解构了
let message = "abcde";
console.log([...message]); // ["a", "b", "c", "d", "e"]
2.9 字符串大小写转换
包括 4 个方法:toLowerCase()、toLocaleLowerCase()、toUpperCase() 和 toLocaleUpperCase()
- toLocaleLowerCase() 和 toLocaleUpperCase() 方法旨在基于特定地区实现
- 通常,如果不知道代码涉及什么语言,则最好使用地区特定的转换方法
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"
2.10 字符串模式匹配方法
2.10.1 match()
这个方法本质上跟 RegExp 对象的 exec() 方法相同
- match()方法接收一个参数,可以是一个正则表达式字符串,也可以是一个 RegExp 对象
let text = "cat, bat, sat, fat";
let pattern = /.at/;
// 等价于 pattern.exec(text)
let matches = text.match(pattern);
// ['cat', index: 0, input: 'cat, bat, sat, fat', groups: undefined]
console.log(matches.index); // 0
console.log(matches[0]); // "cat"
console.log(pattern.lastIndex); // 0
2.10.2 search()
这个方法唯一的参数与 match() 方法一样:正则表达式字符串或 RegExp 对象
- 返回模式第一个匹配的位置索引,如果没找到则返回 -1
let text = "cat, bat, sat, fat";
let pos = text.search(/at/);
console.log(pos); // 1
2.10.3 replace()
为简化子字符串替换操作,ECMAScript 提供了 replace() 方法
- 这个方法接收两个参数
- 第一个参数可以是一个 RegExp 对象或一个字符串(这个字符串不会转换为正则表达式)
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"
- 第二个参数可以是一个字符串或一个函数
第二个参数是字符串的情况下,有几个特殊的字符序列,可以用来插入正则表达式操作的值。ECMA-262 中规定了下表中的值
字符序列 | 替换文本 |
---|---|
$$ | $ |
$& | 匹配整个模式的子字符串 |
$’ | 匹配的子字符串之前的字符串 |
$` | 匹配的子字符串之后的字符串 |
$n | 匹配第 n 个捕获组的字符串,其中 n 是 0~9。比如,$1 是匹配第一个捕获组的字符串,$2 是匹配第二个捕获组的字符串,以此类推。如果没有捕获组,则值为空字符串 |
$nn | 匹配第 nn 个捕获组字符串,其中 nn 是 01~99。比如,$01 是匹配第一个捕获组的字符串,$02 是匹配第二个捕获组的字符串,以此类推。如果没有捕获组,则值为空字符串 |
let text = "cat, bat, sat, fat";
result = text.replace(/(.at)/g, "word ($1)");
console.log(result); // word (cat), word (bat), word (sat), word (fat)
replace()的第二个参数可以是一个函数
这个函数会收到 3 个参数:
- 与整个模式匹配的字符串
- 匹配项在字符串中的开始位置
- 整个字符串
function htmlEscape(text) {
return text.replace(/[<>"&]/g, function(match, pos, originalText) {
switch(match) {
case "<":
return "<";
case ">":
return ">";
case "&":
return "&";
case "\"":
return """;
}
});
}
console.log(htmlEscape("<p class=\"greeting\">Hello world!</p>"));
// "<p class="greeting">Hello world!</p>"
2.10.4 split()
根据传入的分隔符将字符串拆分成数组
- 作为分隔符的参数可以是字符串,也可以是 RegExp 对象(字符串分隔符不会被这个方法当成正则表达式)
- 还可以传入第二个参数,即数组大小,确保返回的数组不会超过指定大小
let colorText = "red,blue,green,yellow";
let colors1 = colorText.split(","); // ["red", "blue", "green", "yellow"]
let colors2 = colorText.split(",", 2); // ["red", "blue"]
let colors3 = colorText.split(/[^,]+/); // ["", ",", ",", ",", ""]
使用正则表达式可以得到一个包含逗号的数组。注意在最后一次调用 split() 时,返回的数组前后包含两个空字符串。这是因为正则表达式指定的分隔符出现在了字符串开头(“red”)和末尾(“yellow”)。
2.11 localeCompare()
比较两个字符串,返回如下 3 个值中的一个
- 如果按照字母表顺序,字符串应该排在字符串参数前头,则返回负值。(通常是-1,具体还要看与实际值相关的实现)
- 如果字符串与字符串参数相等,则返回 0
- 如果按照字母表顺序,字符串应该排在字符串参数后头,则返回正值。(通常是 1,具体还要看与实际值相关的实现)
let stringValue = "yellow";
console.log(stringValue.localeCompare("brick")); // 1
console.log(stringValue.localeCompare("yellow")); // 0
console.log(stringValue.localeCompare("zoo")); // -1
localeCompare() 的独特之处在于,实现所在的地区(国家和语言)决定了这个方法如何比较字符串。在美国,英语是 ECMAScript 实现的标准语言,localeCompare() 区分大小写,大写字母排在小写字母前面。但其他地区未必是这种情况。