注:這章沒什麼能夠理解的,看過一遍就行,因此大致上我把有用的一些東西拷過來給你們看下。
一、字符的Unicode表示法
JavaScript 容許採用\uxxxx
形式表示一個字符,其中xxxx表示字符的 Unicode 碼點。可是,這種表示法只限於碼點在\u0000
~\uFFFF
之間的字符。超出這個範圍的字符,必須用兩個雙字節的形式表示。若是直接在u後面跟上超過0xFFFF的數值(好比u20BB7),JavaScript 會理解成u20BB+7。因爲u20BB是一個不可打印字符,因此只會顯示一個空格,後面跟着一個7。正則表達式
"\uD842\uDFB7" // "?" "\u20BB7" // " 7"
在ES6中作了處理,只要將碼點放入大括號,就能正確解讀該字符。有了這種表示法以後,JavaScript 共有 6 種方法能夠表示一個字符。segmentfault
"\u{20BB7}" // "?" "\u{41}\u{42}\u{43}" // "ABC" let hello = 123; hell\u{6F} // 123 '\u{1F680}' === '\uD83D\uDE80' // true
'\z' === 'z' // true '\172' === 'z' // true '\x7A' === 'z' // true '\u007A' === 'z' // true '\u{7A}' === 'z' // true
二、codePointAt()
對於原來的charAt
和charCodeAt
,是沒法獲取4個字節的字符串的,charCodeAt
方法只能分別返回前兩個字節和後兩個字節的值。而有些漢字是須要4個字節的,好比:漢字「?」(注意,這個字不是「吉祥」的「吉」)的碼點是0x20BB7
。數組
var s = "?"; s.length // 2 s.charAt(0) // '' s.charAt(1) // '' s.charCodeAt(0) // 55362 s.charCodeAt(1) // 57271
因此在ES6中提供了codePointAt
方法,可以正確返回4個字節存儲的字符串。函數
let s = '?a'; s.codePointAt(0) // 134071 s.codePointAt(1) // 57271 s.codePointAt(2) // 97
有的人就要問了,codePointAt
方法爲啥是3個字符(0,1,2)?首先,JavaScript
確定是將'?a'視做3個字符的,只是ES6方法不一樣而已,codePointAt(0)
返回的是第一字符'?',codePointAt(1)
返回的是'?'(共4個字節)的後兩個字節,codePointAt(2)
返回的是'a'。也就是說後兩個字節,codePointAt
方法的結果與charCodeAt
方法相同。
同時,從上面的例子能夠看出,codePointAt方法返回的是碼點的十進制值,若是想要十六進制的值,可使用toString方法轉換一下。this
let s = '?a'; s.codePointAt(0).toString(16) // "20bb7" s.codePointAt(2).toString(16) // "61"
可能這樣看上去感受怪怪的,畢竟只有兩個字符,寫的時候還要去注意0,2,其實有更好的解決辦法,利用for...of
循環,直接看例子:code
let s = '?a'; for (let ch of s) { console.log(ch.codePointAt(0).toString(16)); } // 20bb7 // 61
三、String.fromCodePoint()String.fromCharCode
用於從碼點返回對應字符,可是這個方法不能識別 32
位的 UTF-16
字符(Unicode
編號大於0xFFFF
)。orm
String.fromCharCode(0x20BB7) // "ஷ"
ES6
提供了String.fromCodePoint
方法,能夠識別大於0xFFFF
的字符,彌補了String.fromCharCode
方法的不足。在做用上,正好與codePointAt
方法相反。htm
String.fromCodePoint(0x20BB7) // "?" String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y' // true
四、字符串的遍歷器接口對象
for (let codePoint of 'foo') { console.log(codePoint) } // "f" // "o" // "o"
for...of
循環遍歷,這個遍歷器最大的優勢是能夠識別大於0xFFFF的碼點,傳統的for循環沒法識別這樣的碼點。
五、at()
同上,charAt
不能識別碼點大於0xFFFF
的字符。at
則能夠。
'abc'.at(0) // "a" '?'.at(0) // "?"
六、normalize()normalize()
方法,用來將字符的不一樣表示方法統一爲一樣的形式,這稱爲 Unicode
正規化。
許多歐洲語言有語調符號和重音符號。爲了表示它們,Unicode
提供了兩種方法。一種是直接提供帶重音符號的字符,好比Ǒ(\u01D1)
。另外一種是提供合成符號(combining character
),即原字符與重音符號的合成,兩個字符合成一個字符,好比O(\u004F)
和ˇ(\u030C)
合成Ǒ(\u004F\u030C)
。
'\u01D1'==='\u004F\u030C' //false '\u01D1'.normalize() === '\u004F\u030C'.normalize() // true
normalize方法能夠接受一個參數來指定normalize的方式,參數的四個可選值以下。 NFC,默認參數,表示「標準等價合成」(Normalization Form Canonical Composition),返回多個簡單字符的合成字符。所謂「標準等價」指的是視覺和語義上的等價。 NFD,表示「標準等價分解」(Normalization Form Canonical Decomposition),即在標準等價的前提下,返回合成字符分解的多個簡單字符。 NFKC,表示「兼容等價合成」(Normalization Form Compatibility Composition),返回合成字符。所謂「兼容等價」指的是語義上存在等價,但視覺上不等價,好比「囍」和「喜喜」。(這只是用來舉例,normalize方法不能識別中文。) NFKD,表示「兼容等價分解」(Normalization Form Compatibility Decomposition),即在兼容等價的前提下,返回合成字符分解的多個簡單字符。
七、includes(), startsWith(), endsWith() indexOf
方法,能夠用來肯定一個字符串是否包含在另外一個字符串中。ES6 又提供了三種新方法。
includes():返回布爾值,表示是否找到了參數字符串。 startsWith():返回布爾值,表示參數字符串是否在原字符串的頭部。 endsWith():返回布爾值,表示參數字符串是否在原字符串的尾部。
let s = 'Hello world!'; s.startsWith('Hello') // true s.endsWith('!') // true s.includes('o') // true
這三個方法都支持第二個參數,表示開始搜索的位置。
let s = 'Hello world!'; s.startsWith('world', 6) // true s.endsWith('Hello', 5) // true s.includes('Hello', 6) // false
八、repeat()repeat
方法返回一個新字符串,表示將原字符串重複n次。參數若是是小數,會被取整。若是repeat
的參數是負數或者Infinity
,會報錯。
'x'.repeat(3) // "xxx" 'na'.repeat(2.9) // "nana" 'na'.repeat(0) // "" 'na'.repeat(Infinity) // RangeError 'na'.repeat(-1) // RangeError
可是,若是參數是 0 到-1 之間的小數,則等同於 0,這是由於會先進行取整運算。0 到-1 之間的小數,取整之後等於-0,repeat
視同爲 0。
'na'.repeat(-0.9) // ""
參數NaN
等同於 0。
'na'.repeat(NaN) // ""
若是repeat
的參數是字符串,則會先轉換成數字。
'na'.repeat('na') // "" 'na'.repeat('3') // "nanana"
九、padStart(),padEnd()
若是某個字符串不夠指定長度,會在頭部或尾部補全。padStart()
用於頭部補全,padEnd()
用於尾部補全。
'x'.padStart(5, 'ab') // 'ababx' 'x'.padStart(4, 'ab') // 'abax' 'x'.padEnd(5, 'ab') // 'xabab' 'x'.padEnd(4, 'ab') // 'xaba'
若是原字符串的長度,等於或大於指定的最小長度,則返回原字符串。
'xxx'.padStart(2, 'ab') // 'xxx' 'xxx'.padEnd(2, 'ab') // 'xxx'
若是省略第二個參數,默認使用空格補全長度。
'x'.padStart(4) // ' x' 'x'.padEnd(4) // 'x '
padStart
的常見用途是爲數值補全指定位數。下面代碼生成 10 位的數值字符串。
'1'.padStart(10, '0') // "0000000001" '12'.padStart(10, '0') // "0000000012" '123456'.padStart(10, '0') // "0000123456"
十、模板字符串
用反引號(`)標識,它能夠看成普通字符串使用,也能夠用來定義多行字符串,或者在字符串中嵌入變量。
// 普通字符串 `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 template = ` <ul> <% for(let i=0; i < data.supplies.length; i++) { %> <li><%= data.supplies[i] %></li> <% } %> </ul> `;
上面代碼在模板字符串之中,放置了一個常規模板。該模板使用<%...%>
放置 JavaScript
代碼,使用<%= ... %>
輸出 JavaScript
表達式。
怎麼編譯這個模板字符串呢?
一種思路是將其轉換爲 JavaScript 表達式字符串。
echo('<ul>'); for(let i=0; i < data.supplies.length; i++) { echo('<li>'); echo(data.supplies[i]); echo('</li>'); }; echo('</ul>');
這個轉換使用正則表達式就好了。
let evalExpr = /<%=(.+?)%>/g; let expr = /<%([\s\S]+?)%>/g; template = template .replace(evalExpr, '`); \n echo( $1 ); \n echo(`') .replace(expr, '`); \n $1 \n echo(`'); template = 'echo(`' + template + '`);';
而後,將template封裝在一個函數裏面返回,就能夠了。
let script = `(function parse(data){ let output = ""; function echo(html){ output += html; } ${ template } return output; })`; return script;
將上面的內容拼裝成一個模板編譯函數compile。
function compile(template){ const evalExpr = /<%=(.+?)%>/g; const expr = /<%([\s\S]+?)%>/g; template = template .replace(evalExpr, '`); \n echo( $1 ); \n echo(`') .replace(expr, '`); \n $1 \n echo(`'); template = 'echo(`' + template + '`);'; let script = `(function parse(data){ let output = ""; function echo(html){ output += html; } ${ template } return output; })`; return script; }
compile函數的用法以下。
let parse = eval(compile(template)); div.innerHTML = parse({ supplies: [ "broom", "mop", "cleaner" ] }); // <ul> // <li>broom</li> // <li>mop</li> // <li>cleaner</li> // </ul>
十一、String.raw()String.raw
方法,每每用來充當模板字符串的處理函數,返回一個斜槓都被轉義(即斜槓前面再加一個斜槓)的字符串,對應於替換變量後的模板字符串。
String.raw`Hi\n${2+3}!`; // "Hi\\n5!" String.raw`Hi\u000A!`; // 'Hi\\u000A!'
若是原字符串的斜槓已經轉義,那麼String.raw
不會作任何處理。
String.raw`Hi\\n` // "Hi\\n"
String.raw
的代碼基本以下。
String.raw = function (strings, ...values) { let output = ""; let index; for (index = 0; index < values.length; index++) { output += strings.raw[index] + values[index]; } output += strings.raw[index] return output; }
String.raw
方法能夠做爲處理模板字符串的基本方法,它會將全部變量替換,並且對斜槓進行轉義,方便下一步做爲字符串來使用。
String.raw
方法也能夠做爲正常的函數使用。這時,它的第一個參數,應該是一個具備raw
屬性的對象,且raw
屬性的值應該是一個數組。
String.raw({ raw: 'test' }, 0, 1, 2); // 't0e1s2t'
// 等同於
String.raw({ raw: ['t','e','s','t'] }, 0, 1, 2);