字符串解读
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字节的写法等价 输入true
js对字符的几种体现办法:
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 = 100let 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 = 5let 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