JS数据类型:字符串
字符串
在 JavaScript 中,文本数据被以字符串形式存储,单个字符没有单独的类型。
字符串的内部格式始终是 UTF-16,它不依赖于页面编码。
引号(Quotes)
字符串可以包含在单引号、双引号或反引号中:
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); // 客人清单,多行
看起来很自然,不是吗?但是单引号和双引号可不能这样做。
特殊字符
我们仍然可以通过使用“换行符(newline character)”,以支持使用单引号和双引号来创建跨行字符串。换行符写作 \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 个字节。这样我们就可以插入长代码了。 |
unicode 示例:
alert( "\u00A9" ); // © alert( "\u{20331}" ); // 佫,中文字(长 unicode) alert( "\u{1F60D}" ); // 一个笑脸
所有的特殊字符都以反斜杠字符 \\\\\\\\\\\\\\\\ 开始。它也被称为“转义字符”。
如果我们想要在字符串中插入一个引号,我们也会使用它。
例如:
alert( 'I\'m the Walrus!' ); // I'm the Walrus!
字符串长度,length 属性
length 属性表示字符串长度:
alert( `My\n`.length ); // 3
注意 \n 是一个单独的“特殊”字符,所以长度确实是 3。
访问字符
要获取在 pos 位置的一个字符,可以使用方括号 [pos] 或者调用 str.charAt(pos) 方法。第一个字符从零位置开始:
let str = `Hello`; // 第一个字符 alert( str[0] ); //返回 H alert( str.charAt(0) ); //返回 H // 最后一个字符 alert( str[str.length - 1] ); //返回 o
如果没有找到字符,[] 返回 undefined,而 charAt 返回一个空字符串:
let str = `Hello`; alert( str[1000] ); // undefined alert( str.charAt(1000) ); // ''(空字符串)
我们也可以使用 for..of 遍历字符:
for (let char of str) { alert(char); // H,e,l,l,o(char 变为 "H",然后是 "e",然后是 "l" 等) }
这样的方法只能用于访问字符串,而不能用于修改,例如下面的情况会报错:
let str = 'Hi'; str[0] = 'h'; // error alert( str[0] ); // 无法运行
改变大小写
toLowerCase() 和 toUpperCase() 方法可以改变大小写: alert( 'Interface'.toUpperCase() ); // INTERFACE alert( 'Interface'.toLowerCase() ); // interface alert( 'Interface'[0].toLowerCase() ); // 'i'
查找子字符串
在字符串中查找子字符串有很多种方法。
str.indexOf
第一个方法是 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 开始检索:
let str = 'Widget with id'; alert( str.indexOf('id', 2) ) // 12 这次找到的是另一个id
如果我们需要找某个字符在字符串中的所有出现位置,可以使用循环
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, pos)
还有一个类似的方法 str.lastIndexOf(substr, position),它从字符串的末尾开始搜索到开头。
在 if 测试中 indexOf 有一点不方便。我们不能像这样把它放在 if 中:
let str = "Widget with id"; if (str.indexOf("Widget")) { alert("We found it"); // 不工作! }else{ alert("no no no"); //执行了else的操作 }
上述示例中的 上面那个 alert 不会显示,因为 str.indexOf("Widget") 返回 0(意思是它在起始位置就查找到了匹配项),但是 if 认为 0 表示 false。
所以我们必须这写:
if (str.indexOf("Widget") != -1) { alert("We found it"); // 现在工作了! }
includes,startsWith,endsWith
更先进的方法 str.includes(substr, pos) 根据 str 中是否包含 substr 来返回 true/false。
如果我们需要检测匹配,但不需要它的位置,那么这是正确的选择:
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"
方法 str.startsWith 和 str.endsWith 的功能与其名称所表示的意思相同:
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) ); // ""(空字符串)
不支持负参数(不像 slice),它们被视为 0。
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 个字符