学习笔记|字符串的扩展
1.字符的 Unicode 表示法
es6较早版本支持的码点是用UTF16BE编码(Unicode转换后的程序数据)来编写的,只限于\u0000~\uFFFF,超出这个范围就要用双字节表示,即:
console.log("\u0061") // a console.log("\uD842\uDFB7") // "𠮷"
对于Unicode超出部分并不是很能识别,如果直接在\u后面跟上超过0xFFFF的数值(比如\u20BB7),JavaScript 会理解成\u20BB+7。\u20BB是一个表情符号,后面跟着一个7,如下:
console.log("\u20BB7") // "₻7"
ES6 对这一点做出了改进,只要将码点放入大括号,就能正确解读Unicode。
console.log("\u{20BB7}") // "𠮷" console.log("\u{41}\u{42}\u{43}") // "ABC" let hello = 123; hell\u{6F} // 123 '\u{1F680}' === '\uD83D\uDE80' // true
附上𠮷的各种编码:
2.字符串的遍历
for (let codePoint of 'foo') { console.log(codePoint) } // "f" // "o" // "o"
这个遍历器最大的优点是可以识别大于0xFFFF
的码点,传统的for
循环无法识别这样的码点。
let text = String.fromCodePoint(0x20BB7); for (let i = 0; i < text.length; i++) { console.log(text[i]); } // "�" // "�" for (let i of text) { console.log(i); } // "𠮷"
上面代码中,字符串text
只有一个字符,但是for
循环会认为它包含两个字符(都不可打印),而for...of
循环会正确识别出这一个字符。
3.字符串的转义
JavaScript 规定有5个字符,不能在字符串里面直接使用,只能使用转义形式。
- U+005C:反斜杠(reverse solidus)
- U+000D:回车(carriage return)
- U+2028:行分隔符(line separator)
- U+2029:段分隔符(paragraph separator)
- U+000A:换行符(line feed)
举例来说,字符串里面不能直接包含反斜杠,一定要转义写成\\或者\u005c。
4.模板字符串
传统的 JavaScript 语言,字符串模板通常是
let num = 2 "111"+num+"1" //"11121"
这样的写法比较繁琐,ES6 引入了模板字符串解决这个问题。
let num = 2 `111${num}1` //"11121"
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量(模板字符串中嵌入变量,需要将变量名写在${}
之中)。
// 普通字符串 `In JavaScript '\n' is a line-feed.` // 多行字符串 `In JavaScript this is not legal.` console.log(`string text line 1 string text line 2`); // 字符串中嵌入变量 let name = "Bob", time = "today"; `Hello ${name}, how are you ${time}?`
上面代码中的模板字符串,都是用反引号表示。如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。
let greeting = `\`Yo\` World!`;
大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性,甚至能调用函数。
//运算 let x = 1; let y = 2; `${x} + ${y} = ${x + y}` // "1 + 2 = 3" `${x} + ${y * 2} = ${x + y * 2}` // "1 + 4 = 5" //对象 let obj = {x: 1, y: 2}; `${obj.x + obj.y}` // "3" //函数 function fn() { return "Hello World"; } `foo ${fn()} bar` // foo Hello World bar
由于模板字符串的大括号内部,就是执行 JavaScript 代码,因此如果大括号内部是一个字符串,将会原样输出。
`Hello ${'World'}` // "Hello World"
5.标签模板
标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。
但是,如果模板字符里面有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数。
//不带变量 alert`123` // 等同于 alert(123) //包含变量 let a = 5; let b = 10; tag`Hello ${ a + b } world ${ a * b }`; // 等同于 tag(['Hello ', ' world ', ''], 15, 50); //例子1 let a = 5; let b = 10; function tag(s, v1, v2) { console.log(s[0]); console.log(s[1]); console.log(s[2]); console.log(v1); console.log(v2); return "OK"; } tag`Hello ${ a + b } world ${ a * b}`; // "Hello " // " world " // "" // 15 // 50 // "OK" //例子2 let total = 30; let msg = passthru`The total is ${total} (${total*1.05} with tax)`; function passthru(literals) { let result = ''; let i = 0; while (i < literals.length) { result += literals[i++]; if (i < arguments.length) { //传递给函数的参数的类数组对象 result += arguments[i]; } } return result; } console.log(msg)
“标签模板”的一个重要应用,就是过滤 HTML 字符串,防止用户输入恶意内容。
let sender = '<script>alert("abc")</script>'; let message = SaferHTML`<p>${sender} has sent you a message.</p>`; function SaferHTML(templateData) { let s = templateData[0]; for (let i = 1; i < arguments.length; i++) { let arg = String(arguments[i]); // Escape special characters in the substitution. s += arg.replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">"); // Don't escape special characters in the template. s += templateData[i]; } return s; }
document.write(message)
标签模板的另一个应用,就是多语言转换(国际化处理)
i18n`Welcome to ${siteName}, you are visitor number ${visitorNumber}!` // "欢迎访问xxx,您是第xxxx位访问者!"
模板处理函数的第一个参数(模板字符串数组),还有一个raw属性。
tag`First line\nSecond line` function tag(strings) { console.log(strings.raw[0]); // strings.raw[0] 为 "First line\\nSecond line" // 打印输出 "First line\nSecond line" } console.log("First line\nSecond line") //"First line //Second line"
strings.raw数组就是["First line\\nSecond line"],strings.raw 数组会将\n视为\\和n两个字符,而不是换行符。这是为了方便取得转义之前的原始模板而设计的。