字符串中的字符怎么表示(字符串的解读和标签模板)
字符串解读
es6加强了对Unicode 的支持 ,允许\uxxxx的形式展现一个字符 ,例如:
console.log(\u0061); // 打印 a\u后面的为字符的 Unicode 码点 \u 后面4位 xxxx
但是这种写法只识别 \u0000 到 \UFFFF 之间的字符,超出需要使用两个双字节表示 ,例如:
console.log(\uD842\uDFB7); // 打印 吉如果说超出了\uxxxx字节的范围 ,则为两个字节的拼接 ,例如:
console.log(\u20BB7); // 输出 7 \u20BB系统识别为空 console.log(\u00617); // 输出 a7\u0061识别为a ,由于7超出了这个字节 ,所以为\u0061+7 ,结果为a7
es6对 Unicode 的支持进行了加强 ,如果超出了两个字节 ,放入大括号内即可正常解读
console.log("\u{20BB7}"); // 打印 吉 // 只要将码点放入大括号即可正确解读 console.log(\u{41}\u{42}\u{43}); // 输出ABC大括号与双字节的写法是等价的
console.log(\u{1F680} == \uD83D\uDE80); // 大括号与4字节的写法等价 输出truejs对字符的几种表现方法:
console.log(\z === z); console.log(\172 === z); console.log(\x7A === z); console.log(\u007A === z); console.log(\u{7A} === z); console.log(z === z);字符串的遍历
字符串遍历for...of
for (let codePoint of foo) { console.log(codePoint); // f o o }其实一般的遍历 ,例如for,也可以遍历字符串 ,但是for无法识别大于0xFFFF的码点 ,而for...of则可以识别
let text = String.fromCodePoint(0x20BB7) // for循环 for (let i = 0; i < text.length; i++) { console.log(text[i]); // 空 } // for---of可以识别 大于0xFFFF的码点 , 而传统的for无法识别 for (let i of text) { console.log(i); // 吉 }有些时候 ,我们在用JSON.stringify转字符串的时候 ,发现转译的字符串多了几个\
根据标准,JSON数据必须是 UTF-8 编码 。但是JSON.stringify()方法有可能返回不符合 UTF-8 标准的字符串 。
UTF-8 标准规定 ,0xD800到0xDFFF之间的码点 ,不能单独使用 ,必须配对使用。比如 ,\uD834\uDF06是两个码点 ,但是必须放在一起配对使用 ,代表字符? 。这是为了表示码点大于0xFFFF的字符的一种变通方法 。单独使用\uD834和\uDF06这两个码点是不合法的 ,或者颠倒顺序也不行 ,因为\uDF06\uD834并没有对应的字符 。
JSON.stringify()的问题在于 ,它可能返回0xD800到0xDFFF之间的单个码点 。 JSON.stringify(\u{D834}) // "\u{D834}"所以 es2019对JSON.stringify()做出了改变,如果遇到0xD800到0xDFFF之间的单个码点 ,或者不存在的配对形式 ,它会返回转义字符串,留给应用自己决定下一步的处理 。
console.log(JSON.stringify(\u{D834})) // ""\\uD834"" console.log(JSON.stringify(\uDF06\uD834)) // ""\\uD834""模板字符串
1 、模板字符串识别标签 ,并却可以识别多行内容 ,传统的写法需要用+ 号连接,
2 、模板字符串识别空格 let context = document.getElementById(context) let str = `<div>东方 不败</div> <div>东方求败</div>` console.log(context.innerHTML = str); // 页面显示 东方 不败传统的字符串插值 ,需要使用"字符"+100+"值"的形式 ,用 + 拼接 ,值是不能嵌套在引号当中的 ,否则会解译为字符串 。
console.log("<div>东方不败有" + 100 + "元</div>")模板字符串直接使用${xxx}即可在字符串中插值 ,并且在里面可以使用表达式以及调用函数 。
let str2 = `<div>东方不败${100}</div>` // 东方不败 100 // 表达式 let s = 100 let str3 = `<div>东方不败${s == 100 ? 有100元 : 没有100元}</div>` // 东方不败有100元 // 调用函数 let str4 = `<div>调用函数:${text2()}</div>` function text2() { return 东方不败 } let context2 = document.getElementById(context2) console.log(context2.innerHTML = str4); // 页面显示 调用函数:东方不败模板字符串可以嵌套使用 ,此处用的是map遍历结构 ,需要注意的是 ,forEach是无法在此遍历结构的 ,会直接报错,因为forEach会改变原数组 ,而map则不会(数组为基础类型时原数组不变) 。
let context3 = document.getElementById(context3) let arr = [{ name: 字符串, index: 01 }, { name: 字符串, index: 02 }] let s2 = ` <div>模板字符串嵌套:${ arr.map(el => ` <div>${el.name}</div> <div>${el.index}</div> `) }</div> ` context3.innerHTML = s2结果:
标签模板
函数名跟上模板字符串 ,则为标签模板,左边是函数 ,右边实际上是函数参数 ,例如:
alert `hello` // 等同于 alert([hello])此处的alert是函数,紧跟在后面的模板字符串就是它的参数 ,这里会触发alert弹框 ,展示hello
但如果模板字符串有变量 ,就不是简单的调用 ,而是会先将模板字符串先处理成多个参数 ,再调用函数 ,例如: let a = 5 let b = 10 // alert `hello ${ a + b} , word ${ a * b }` tag(`hello ${ a + b} , word ${ a * b }`)此处的tag等同于 tag([hello , , word , ],15,50) ,在这里 ,模板字符串前有一个tag ,这个tag是一个函数,整个表达式的返回值就是tag函数处理模板字符串后返回的值 ,返回结果可以看上面alert打印的内容 。
实际上是将tag转换成了: // 实际上转换成了 function tag(stringArr, value1, value2) { // ...... } // 或者 function tag(stringArr, ...values) { console.log(stringArr, values); // ...... }1 、tag函数的第一个参数是一个数组 ,整个数组是模板字符串中没有变量替换的部分。
2 、变量的替换,只发生在数组的第一个成员于第二个成员之间 ,第二个成员与第三个成员之间 ,以此类推 。
3 、tag函数的其他参数,都是模板字符串各个变量被替换后的值 。这里的模板字符串有两个参数 ,所以这里会接收 value1 , value2 两个参数。
例如:
第一个参数:[hello , , word , ]
第二个参数:15
第三个参数:50
其实也就是 tag([hello , , word , ],15,50)这里再举一个例子: 下面就是关于标签模板是怎样将字符串与值拼接的过程 ,最终展现的就是标签模板编译后的结果
let total = 30; // 变量 let msg = passthru `The total is ${total} (${total*1.05} with tax)`; function passthru(literals) { //literals : [The total is , (, with tax), raw: Array(3)] let result = let i = 0 while (i < literals.length) { result += literals[i++]; if (i < arguments.length) { /* arguments: 0:[The total is , (, with tax), raw: Array(3)] 1 : 30 2 : 31.5 */ console.log(arguments); // 参数的数组 result += arguments[i] } } return result }输出结果:The total is 30 (31.5 with tax)
步骤拆解:
1: passthru函数的参数literals就是标签模板的参数[The total is , (, with tax), raw: Array(3)]
2: while 遍历了数组参数的长度 ,并且在内部进行判断
3: if中的arguments就是参数的数组 ,这一步就是关键的字符串与值得拼接 ,拼接的步骤如下: while遍历 ,如果参数为true则循环遍历 ,直到false终止 遍历内容如下: The total is 30 ( 31.5前面说过了:变量的替换 ,只发生在数组的第一个成员于第二个成员之间,第二个成员与第三个成员之间 ,以此类推 。所以此处也是这样处理的 ,最后返回的结果就是The total is 30 (31.5 with tax) 。
恶意输入
标签模板还有一个重要的作用就是防止用户恶意输入,如果用户在输入框恶意嵌套标签是非常不安全的行为。
let sender = <script>alert("恶意代码")</cript> function SaferHTML(templateData) { let s = templateData[0] for (let i = 1; i < arguments.length; i++) { let arg = String(arguments[i]) s +=arg.replace(/&/g,"&") .replace(/</g,"<") .replace( />/g,">") // 过滤 转义 &为&字符; <为<字符; >为>字符; s += templateData[i] } return s }此处将用户嵌套的script标签进行了转译 ,&为&字符 、<为<字符 、 >为>字符
let message = SaferHTML `<p>${sender}个人信息</p>` console.log(message); // 打印 <p><script>alert("恶意代码")</script> 个人信息</p>由于我的编译器会自动格式化,所以用 sxxxcript 代替 script
标签模板可以做多语言转(国际化)
i18n `Welcome to ${userName}, you are visitor number ${visitorNumber}!`甚至可以在标签模板嵌套其他语言
jsx ` <div> <input ref=input onChange=${this.handleChange} defaultValue=${this.state.value} /> ${this.state.value} </div> ` // 此处就是通过jsx函数 ,将DOM字符串转换为React对象模板处理函数的第一个参数,也就是非参数的模板字符串数组 ,有一个raw属性
console.log(`abc`) // [abc,row:Array[1]] // 这个raw保存的是转义后的原字符串这个数组后面的raw保存的是转义后的原字符串 。
案例源码:https://gitee.com/wang_fan_w/es6-science-institute
如果觉得这篇文章对你有帮助 ,欢迎点亮一下star
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!