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

LishiJ發表於2017-12-18

ECMAScript6/ES6 入門

let和const命令
變數的解構賦值

五、字串的擴充套件

注:這章沒什麼可以理解的,看過一遍就行,所以大體上我把有用的一些東西拷過來給大家看下。
1、字元的Unicode表示法
JavaScript 允許採用uxxxx形式表示一個字元,其中xxxx表示字元的 Unicode 碼點。但是,這種表示法只限於碼點在u0000~uFFFF之間的字元。超出這個範圍的字元,必須用兩個雙位元組的形式表示。如果直接在u後面跟上超過0xFFFF的數值(比如u20BB7),JavaScript 會理解成u20BB+7。由於u20BB是一個不可列印字元,所以只會顯示一個空格,後面跟著一個7。

"uD842uDFB7"
// "?"

"u20BB7"
// " 7"

在ES6中做了處理,只要將碼點放入大括號,就能正確解讀該字元。有了這種表示法之後,JavaScript 共有 6 種方法可以表示一個字元。

"u{20BB7}"
// "?"

"u{41}u{42}u{43}"
// "ABC"

let hello = 123;
hellu{6F} // 123

`u{1F680}` === `uD83DuDE80`
// true
`z` === `z`  // true
`172` === `z` // true
`x7A` === `z` // true
`u007A` === `z` // true
`u{7A}` === `z` // true

2、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方法轉換一下。

let s = `?a`;

s.codePointAt(0).toString(16) // "20bb7"
s.codePointAt(2).toString(16) // "61"

可能這樣看上去感覺怪怪的,畢竟只有兩個字元,寫的時候還要去注意0,2,其實有更好的解決辦法,利用for...of迴圈,直接看例子:

let s = `?a`;
for (let ch of s) {
  console.log(ch.codePointAt(0).toString(16));
}
// 20bb7
// 61

3、String.fromCodePoint()
String.fromCharCode用於從碼點返回對應字元,但是這個方法不能識別 32 位的 UTF-16 字元(Unicode 編號大於0xFFFF)。

String.fromCharCode(0x20BB7)
// "ஷ"

ES6 提供了String.fromCodePoint方法,可以識別大於0xFFFF的字元,彌補了String.fromCharCode方法的不足。在作用上,正好與codePointAt方法相反。

String.fromCodePoint(0x20BB7)
// "?"
String.fromCodePoint(0x78, 0x1f680, 0x79) === `xuD83DuDE80y`
// true

4、字串的遍歷器介面

for (let codePoint of `foo`) {
  console.log(codePoint)
}
// "f"
// "o"
// "o"

for...of迴圈遍歷,這個遍歷器最大的優點是可以識別大於0xFFFF的碼點,傳統的for迴圈無法識別這樣的碼點。
5、at()
同上,charAt不能識別碼點大於0xFFFF的字元。at則可以。

`abc`.at(0) // "a"
`?`.at(0) // "?"

6、normalize()
normalize()方法,用來將字元的不同表示方法統一為同樣的形式,這稱為 Unicode 正規化。
許多歐洲語言有語調符號和重音符號。為了表示它們,Unicode 提供了兩種方法。一種是直接提供帶重音符號的字元,比如Ǒ(u01D1)。另一種是提供合成符號(combining character),即原字元與重音符號的合成,兩個字元合成一個字元,比如O(u004F)ˇ(u030C)合成Ǒ(u004Fu030C)

`u01D1`===`u004Fu030C` //false

`u01D1`.normalize() === `u004Fu030C`.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),即在相容等價的前提下,返回合成字元分解的多個簡單字元。

7、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

8、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"

9、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"

10、模板字串
用反引號(`)標識,它可以當作普通字串使用,也可以用來定義多行字串,或者在字串中嵌入變數。

// 普通字串
`In JavaScript `
` 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}?`

11、例項:模板編譯

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 = /<%([sS]+?)%>/g;

template = template
  .replace(evalExpr, ``); 
  echo( $1 ); 
  echo(``)
  .replace(expr, ``); 
 $1 
  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 = /<%([sS]+?)%>/g;

  template = template
    .replace(evalExpr, ``); 
  echo( $1 ); 
  echo(``)
    .replace(expr, ``); 
 $1 
  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>

11、String.raw()
String.raw方法,往往用來充當模板字串的處理函式,返回一個斜槓都被轉義(即斜槓前面再加一個斜槓)的字串,對應於替換變數後的模板字串。

String.raw`Hi
${2+3}!`;
// "Hi\n5!"

String.raw`Hiu000A!`;
// `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);

相關文章