关于前端:字符串的解读和标签模板

3次阅读

共计 4964 个字符,预计需要花费 13 分钟才能阅读完成。

字符串解读

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

es6Unicode 的反对进行了增强,如果超出了两个字节,放入大括号内即可失常解读

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 标准规定,0xD8000xDFFF 之间的码点,不能独自应用,必须配对应用。比方,\uD834\uDF06是两个码点,然而必须放在一起配对应用,代表字符 𝌆。这是为了示意码点大于0xFFFF 的字符的一种变通方法。独自应用 \uD834\uDF06这两个码点是不非法的,或者颠倒程序也不行,因为 \uDF06\uD834 并没有对应的字符。
JSON.stringify()的问题在于,它可能返回 0xD8000xDFFF之间的单个码点。

JSON.stringify('\u{D834}') // "\u{D834}"

所以 es2019JSON.stringify() 做出了扭转,如果遇到 0xD8000xDFFF之间的单个码点,或者不存在的配对模式,它会返回本义字符串,留给利用本人决定下一步的解决。

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,"&amp")
                    .replace(/</g,"&lt")
                    .replace(/>/g,"&gt") 
     // 过滤 本义 & 为 &amp 字符;  < 为 &lt 字符;  > 为 &gt 字符;
             s += templateData[i]
            }
            return s
        }

此处将用户嵌套的 script 标签进行了转译,& 为 &amp 字符< 为 &lt 字符> 为 &gt 字符

let message = SaferHTML `<p>${sender}个人信息 </p>`
console.log(message);
// 打印 <p>&lt;script&gt;alert("恶意代码")&lt;/script&gt; 个人信息 </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

正文完
 0