字串解讀
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 = 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='https://www.cnblogs.com/wang-fan-w/archive/2023/02/14/${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
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/543925.html
標籤:其他
上一篇:云小課|使用SpringBoot快速構建FunctionGraph HTTP函式
下一篇:記錄--前端實作登錄拼圖驗證

