字符串
引号
字符串可以包含在单引号、双引号或反引号中:
let single = 'single-quoted';
let double = "double-quoted";
let backticks = `backticks`;
单引号和双引号基本相同,但是,反引号允许我们通过${…}将任何表达式嵌入到字符串中:
function sum(a, b) {
return a + b;
}
alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3.
而且反引号可以允许字符串跨行,使用单引号或双引号来实现的化,会出现错误。
let guestList = `Guests:
* John
* Pete
* Mary
`;
alert(guestList); // 客人清单,多行
特殊字符
换行符 \n
let guestList = "Guests:\n * John\n * Pete\n * Mary";
alert(guestList); // 一个多行的客人列表
举例:这两行描述的是一样的,只是书写方式不同:
let str1 = "Hello\nWorld"; // 使用“换行符”创建的两行字符串
// 使用反引号和普通的换行创建的两行字符串
let str2 = `Hello
World`;
alert(str1 == str2); // true
另外一些不常见的特殊字符
字符 | 描述 |
---|---|
\n | 换行 |
\r | 回车:不单独使用。Windows 文本文件使用两个字符 \r\n 的组合来表示换行。 |
\' , \" | 引号 |
\\ | 反斜线 |
\t | 制表符 |
\b , \f , \v | 退格,换页,垂直标签 —— 为了兼容性,现在已经不使用了。 |
\xXX | 具有给定十六进制 Unicode XX 的 Unicode 字符,例如:'\x7A' 和 'z' 相同。 |
\uXXXX | 以 UTF-16 编码的十六进制代码 XXXX 的 unicode 字符,例如 \u00A9 —— 是版权符号 © 的 unicode。它必须正好是 4 个十六进制数字。 |
\u{X…XXXXXX} (1 到 6 个十六进制字符) | 具有给定 UTF-32 编码的 unicode 符号。一些罕见的字符用两个 unicode 符号编码,占用 4 个字节。这样我们就可以插入长代码了。 |
示例:
alert( "\u00A9" ); // ©
alert( "\u{20331}" ); // 佫,罕见的中国象形文字(长 unicode)
alert( "\u{1F60D}" ); // 😍,笑脸符号(另一个长 unicode)
所有的特殊字符都以反斜杠字符 \
开始。它也被称为“转义字符”。
如果我们想要在字符串中插入一个引号,我们也会使用它。
alert( 'I\'m the Walrus!' ); // I'm the Walrus!
但是,我们可以直接使用双引号或者反引号直接解决这个问题
alert( `I'm the Walrus!` ); // I'm the Walrus!
注意,如果想得到反斜杠的化,需要书写两次 \
alert( `The backslash: \\` ); // The backslash: \
字符串长度
length 属性表示字符串长度:
alert( `My\n`.length ); // 3
// 注意 \n 是一个单独的特殊字符,所以长度是3
//length 是一个属性,掌握其他编程语言的话,有时会错误地调用 str.length() 而不是 str.length。这是行不通的。
//请注意 str.length 是一个数字属性,而不是函数。后面不需要添加括号。
访问字符
要获取在 pos
位置的一个字符,可以使用方括号 [pos]
或者调用 str.charAt(pos) 方法。第一个字符从零位置开始:
let str = `Hello`;
// 第一个字符
alert( str[0] ); // H
alert( str.charAt(0) ); // H
// 最后一个字符
alert( str[str.length - 1] ); // o
方括号是获取字符的一种现代化方法,而 charAt
是历史原因才存在的。
它们之间的唯一区别是,如果没有找到字符,[]
返回 undefined
,而 charAt
返回一个空字符串:
let str = `Hello`;
alert( str[1000] ); // undefined
alert( str.charAt(1000) ); // ''(空字符串)
当然也可以使用 for … of 遍历字符
for (let char of "Hello") {
alert(char); // H,e,l,l,o(char 变为 "H",然后是 "e",然后是 "l" 等)
}
字符串是不可变的
let str = 'Hi';
str[0] = 'h'; // error
alert( str[0] ); // 无法运行
//解决方法一般是创建一个新的字符串,并将其分配给 str 而不是以前的字符串
let str = 'Hi';
str = 'h' + str[1]; // 替换字符串
alert( str ); // hi
改变大小写
alert( 'Interface'.toUpperCase() ); // INTERFACE
alert( 'Interface'.toLowerCase() ); // interface
//某一个字符变成小写
alert( 'Interface'[0].toLowerCase() ); // 'i'
查找子字符串
法一:str.indexOf(substr,pos)
它从给定位置 pos
开始,在 str
中查找 substr
,如果没有找到,则返回 -1
,否则返回匹配成功的位置。
let str = 'Widget with id';
alert( str.indexOf('Widget') ); // 0,因为 'Widget' 一开始就被找到
alert( str.indexOf('widget') ); // -1,没有找到,检索是大小写敏感的
alert( str.indexOf("id") ); // 1,"id" 在位置 1 处(……idget 和 id)
//如果要查找下一个 id,因为第一次出现位置是1,那么查询下一个位置就是从2开始
alert( str.indexOf('id', 2) ) // 12
//如果我们对所有存在位置都感兴趣,那么在循环中使用这个
let str = 'As sly as a fox, as strong as an ox';
let target = 'as'; // 这是我们要查找的目标
let pos = 0;
while (true) {
let foundPos = str.indexOf(target, pos);
if (foundPos == -1) break;
alert( `Found at ${foundPos}` );
pos = foundPos + 1; // 继续从下一个位置查找
}
//相同算法可以简写
let str = "As sly as a fox, as strong as an ox";
let target = "as";
let pos = -1;
while ((pos = str.indexOf(target, pos + 1)) != -1) {
alert( pos );
}
这里,我们看一种类似的方法,str.lastIndexOf(substr,position),它从字符串的末尾开始搜索到开头,它会以相反的顺序列出这些事件。
在 if 测试中 indexOf 有一些方便,下面这样是不行的
let str = "Widget with id";
if (str.indexOf("Widget")) {
alert("We found it"); // 不工作!
}
因为找到的位置是0,而我们的 if 认为0表示 false。所以我们应该检查 -1。
let str = "Widget with id";
if (str.indexOf("Widget") != -1) {
alert("We found it"); // 现在工作了!
}
按位 NOT 技巧
它将数字转换为 32-bit 整数(如果存在小数部分,则删除小数部分),然后对其二进制表示形式中的所有位均取反。
实际上,这意味着一件很简单的事儿:对于 32-bit 整数,~n
等于 -(n+1)
。
alert( ~2 ); // -3,和 -(2+1) 相同
alert( ~1 ); // -2,和 -(1+1) 相同
alert( ~0 ); // -1,和 -(0+1) 相同
alert( ~-1 ); // 0,和 -(-1+1) 相同
includes,startsWith,endsWith
alert( "Widget with id".includes("Widget") ); // true
alert( "Hello".includes("Bye") ); // false
// str.includes 的第二个可选参数是开始搜索的起始位置
alert( "Midget".includes("id") ); // true
alert( "Midget".includes("id", 3) ); // false, 从位置 3 开始没有 "id"
alert( "Widget".startsWith("Wid") ); // true,"Widget" 以 "Wid" 开始
alert( "Widget".endsWith("get") ); // true,"Widget" 以 "get" 结束
获取子字符串
JavaScript 中有三种获取字符串的方法:substring
、substr
和 slice
。
str.slice(start [, end])
返回字符串从 start 到(但不包括)end 的部分。
let str = "stringify";
alert( str.slice(0, 5) ); // 'strin',从 0 到 5 的子字符串(不包括 5)
alert( str.slice(0, 1) ); // 's',从 0 到 1,但不包括 1,所以只有在 0 处的字符
如果没有第二个参数, slice 会一直运行到字符串末尾
let str = "stringify";
alert( str.slice(2) ); // 从第二个位置直到结束
// start/end 也有可能是负值。它们的意思是起始位置从字符串结尾计算:
let str = "stringify";
// 从右边的第四个位置开始,在右边的第一个位置结束
alert( str.slice(-4, -1) ); // 'gif'
str.substring(start [, end])
返回字符串在 start
和 end
之间的部分。
这与 slice
几乎相同,但它允许 start
大于 end
。
let str = "stringify";
// 这些对于 substring 是相同的
alert( str.substring(2, 6) ); // "ring"
alert( str.substring(6, 2) ); // "ring"
// ……但对 slice 是不同的:
alert( str.slice(2, 6) ); // "ring"(一样)
alert( str.slice(6, 2) ); // ""(空字符串)
str.substr(start [, length])
返回字符串从 start
开始的给定 length
的部分。
与以前的方法相比,这个允许我们指定 length
而不是结束位置:
let str = "stringify";
alert( str.substr(2, 4) ); // 'ring',从位置 2 开始,获取 4 个字符
第一个参数可能是负数,从结尾算起:
let str = "stringify";
alert( str.substr(-4, 2) ); // 'gi',从第 4 位获取 2 个字符
这些方法稍微总结一下
方法 | 选择方式…… | 负值参数 |
---|---|---|
slice(start, end) | 从 start 到 end (不含 end ) | 允许 |
substring(start, end) | start 与 end 之间(包括 start ,但不包括 end ) | 负值代表 0 |
substr(start, length) | 从 start 开始获取长为 length 的字符串 | 允许 start 为负数 |
比较字符串
要注意的地方:
- 小写字母总是大于大写字母
- 带变音符号的字母存在“乱序”的情况
alert( 'a' > 'Z' ); // true
alert( 'Österreich' > 'Zealand' ); // true
str.codePointAt(pos)
返回在 pos 位置的字符代码
// 不同的字母有不同的代码
alert( "z".codePointAt(0) ); // 122
alert( "Z".codePointAt(0) ); // 90
String.fromCodePoint(code)
通过数字 code 来创建字符
alert( String.fromCodePoint(90) ); // Z