ES6學習摘要(03)(新人學習)

ECMAScript6/ES6 入門

let和const命令
變量的解構賦值html

5、字符串的擴展

注:這章沒什麼能夠理解的,看過一遍就行,因此大致上我把有用的一些東西拷過來給你們看下。
一、字符的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()
對於原來的charAtcharCodeAt,是沒法獲取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);
相關文章
相關標籤/搜索