在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ HTML/ 模版字符串
生成器
箭頭函數(shù)
繼續(xù)迭代器
未來前景
簡介
非結(jié)構(gòu)化賦值
迭代器和 for-of 循環(huán)
代理
符號
模版字符串
let 和 const
容器
模塊

模版字符串

反引號的基礎(chǔ)知識

ES6 引入了一種稱為模板字符串的新字符串文字語法 。它們看起來與普通字符串類似,除了他們使用反引號字符 ` 而不是通常的引號 ‘ 或 ” 。在最簡單的情況下,他們真的只是字符串:

context.fillText(`Ceci n'est pas une cha?ne.`, x, y);

但是,這些被稱為“模板字符串”,而不是“只是使用了反引號的無聊普通的舊字符串”,總是有原因的。模板字符串能給 JavaScript 帶來簡單的字符串插值。也就是說,他們是一個(gè)非常漂亮的,方便的方式將 JavaScript 的值插入到字符串中。

有不計(jì)其數(shù)的方式來使用這一點(diǎn),但一個(gè)溫暖我心的是一個(gè)不起眼的錯(cuò)誤信息:

function authorize(user, action) {
  if (!user.hasPrivilege(action)) {
    throw new Error(
      `User ${user.name} is not authorized to do ${action}.`);
  }
}

在這個(gè)例子中,$ {user.name} 和 $ {action} 被稱為模板替換。 JavaScript 會將 user.name 和 action 的值放置到結(jié)果字符串中。這可能會產(chǎn)生類似于用戶 jorendorff 無權(quán)玩曲棍球這樣的消息。 (這是真的。我沒有曲棍球許可。)

到目前為止,這僅僅是一個(gè)為 + 運(yùn)算稍有更好的語法。你可能期望的更多一些的細(xì)節(jié):

  • 模塊字符串中的代碼可以是任何 JavaScript 的表達(dá)式,所以函數(shù)調(diào)用,算術(shù)等操作都是允許的。(如果你真的愿意,你甚至可以嵌套一個(gè)模版字符串于另一個(gè)模板字符串中,我稱之為 template inception。)

  • 如果一個(gè)值不是一個(gè)字符串,則按照一般規(guī)則將其轉(zhuǎn)換為字符串。例如,如果 action 是一個(gè)對象,它的 .toString() 方法將被調(diào)用。

  • 如果你需要在一個(gè)字符串模板內(nèi)寫反引號,你必須在其前面用反斜杠:"\ ` " 這與字符串中使用 “ ' ” 的方法是一樣的。

  • 同樣,如果你需要 在模板中的字符串中包括這兩個(gè)字符 $ {,雖然我不知道你為什么需要這么做,但你可以用反斜杠來進(jìn)行轉(zhuǎn)義:寫成 ` \${ or ${\ `。

與普通的字符串不同,模版字符串能夠?qū)懗啥嘈?

$("#warning").html(`
  <h1\>Watch out!</h1\>
  <p>Unauthorized hockeying can result in penalties
  of up to ${maxPenalty} minutes.</p>
 `);

在模版字符串中所有的空格,包括新行和縮進(jìn),在輸出中都能一字不差的輸出。

好了,因?yàn)槲疑现艿某兄Z,我對你們頭腦的健康負(fù)有責(zé)任。所以,快速的給你們一個(gè)警告:從這里開始,事情將會變得有點(diǎn)緊張。你現(xiàn)在可以停止閱讀了,你可以先去喝杯咖啡并享受下你的未受損害且還沒變糊涂的腦袋。真的,走回頭路也不是什么羞恥的事。在證明了船舶能穿越赤道而不會被海怪破壞,或是從地球的邊緣掉下去后,Lopes Gon?alves 繼續(xù)探索了整個(gè)南半球了嗎?不,他回頭了。他回家了,并吃了一頓不錯(cuò)的午餐。你也很喜歡吃午飯吧?

反引號的未來

讓我們聊一些模版字符串不能做的東西。

  • 他們不能為您自動(dòng)轉(zhuǎn)義特殊字符。為了避免跨站點(diǎn)腳本漏洞,你仍然必須仔細(xì)地處理不可信數(shù)據(jù),就像你串聯(lián)普通的字符串一樣。
  • 他們就如何與國際化庫進(jìn)行交互(一個(gè)幫助你的代碼對不同的用戶說不同的語言)并沒明顯定義。模板字符串不處理語言特定格式的數(shù)字和日期,更不用說復(fù)數(shù)了。
  • 他們不是模版庫的替代品,比如 Mustache 或者 Nunjucks。
    模版字符串沒有循環(huán)的內(nèi)置語法。舉例來說,從一個(gè)數(shù)組中創(chuàng)建一個(gè) HTML 表格的行。模版字符串甚至沒有條件語句。(是的,你在這里可以使用模版開始,但是對我而言,如果你這么做的話,這看起來像是一個(gè)笑話。)

ES6 在模板字符串上提供一個(gè)額外的功具使得 JS 開發(fā)人員和庫設(shè)計(jì)人員可以解決這些限制。這種功能被稱為標(biāo)簽?zāi)0濉?/p>

標(biāo)簽?zāi)0宓恼Z法很簡單。他們只是在開反引號之前加上一個(gè)額外的標(biāo)簽的模板字符串。在我們的第一個(gè)例子中,該標(biāo)簽是 SaferHTML,我們要使用這個(gè)標(biāo)簽來嘗試解決上面列出的第一個(gè)限制:自動(dòng)轉(zhuǎn)義特殊字符。

需要注意的是,SaferHTML不是由 ES6 標(biāo)準(zhǔn)庫提供的。我們將在下面自己來實(shí)現(xiàn)它。

var message =
  SaferHTML`<p>${bonk.sender} has sent you a bonk.</p>`;

這里的標(biāo)記是一個(gè)單個(gè)標(biāo)識符 SaferHTML,但是標(biāo)簽也可以是一個(gè)屬性,比如 SaferHTML.escape,或甚至是一個(gè)方法調(diào)用,比如 SaferHTML.escape({unicodeControlCharacters:false})。 (準(zhǔn)確地說,任何 ES6 的 MemberExpression 或 CallExpression 都可以作為標(biāo)記。)

我們看到,未標(biāo)記的模板字符串只是簡單字符串連接的簡寫。標(biāo)簽?zāi)0宀磐耆莿e的東西的簡寫,那就是:函數(shù)調(diào)用。

上面的代碼等價(jià)于:

var message =
  SaferHTML(templateData, bonk.sender);

其中,templateData 是模板的所有字符串部分的一個(gè)不變的數(shù)組。其是為我們的 JS 引擎創(chuàng)建的。這里的數(shù)組具有兩個(gè)元素,因?yàn)樵跇?biāo)簽?zāi)0逯杏袃蓚€(gè)通過替代隔開的字符串部分。所以 templateData 會看起來像 Object.freeze(["< p>", " has sent you a bonk.< /p>"]。

(其實(shí) templateData 存在不止一個(gè)屬性。但在這篇文章中,我們將不會使用它,但我會為了完整性而提到它:templateData.raw 。這是包含標(biāo)簽?zāi)0逯械乃凶址糠值牧硪粋€(gè)數(shù)組,但此時(shí)正如他們在源代碼中的樣子,他們都原封不動(dòng)地包含了轉(zhuǎn)義序列,如 \n,而不是被轉(zhuǎn)換成新的一行或著等等。標(biāo)準(zhǔn)的標(biāo)簽 String.raw 使用這些原始字符串。)

這使得 SaferHTML 功能能隨意解釋字符串,或者是其一百萬種可能的替換方式。

在繼續(xù)閱讀前,也許你想嘗試了解到底什么是 SaferHTML 應(yīng)該做的,然后再嘗試親手實(shí)現(xiàn)它。畢竟,這只是一個(gè)功能。你可以在火狐瀏覽器的開發(fā)者控制臺上測試你的代碼。

這里是一個(gè)可能的答案(也可作為依據(jù))。

function SaferHTML(templateData) {
  var s = templateData[0];
  for (var i = 1; i < arguments.length; i++) {
    var arg = String(arguments[i]);

    // Escape special characters in the substitution.
    s += arg.replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;");

    // Don't escape special characters in the template.
    s += templateData[i];
  }
  return s;
}

通過這個(gè)定義,標(biāo)簽?zāi)0?SaferHTML<p>${bonk.sender} has sent you a bonk.</p> 可能擴(kuò)展成字符串 "<p>ES6&lt;3er has sent you a bonk.</p>"。你的用戶是安全的,即使一個(gè)惡意命名的用戶,比如 Hacker Steve <script>alert('xss');</script>,就給他們一個(gè)猛擊。別管他們到底想干嘛。

(順便說一句,如果函數(shù)使用 arguments 對象的方式沉重地打擊了你。請?jiān)谙轮荜P(guān)注,ES6 的另一個(gè)新的功能,我想你可能會喜歡。)

單單一個(gè)例子是不夠的顯示標(biāo)簽?zāi)0宓撵`活性的。讓我們回顧我們早期的模板字符串列表的限制,來看看還有什么可以做。

  • 模板字符串不自動(dòng)進(jìn)行特殊字符的轉(zhuǎn)義。但是,正如我們所看到的,使用標(biāo)簽?zāi)0?,你可以用一個(gè)標(biāo)簽自己解決問題。事實(shí)上,你可以做很多比這更好的事情。

    從安全的角度來看,我的 SaferHTML 的功能相當(dāng)薄弱。在 HTML 中, 不同的地方的轉(zhuǎn)義字符需要以不同的方式進(jìn)行轉(zhuǎn)義; 而 SaferHTML 不進(jìn)行轉(zhuǎn)義。但通過一些努力,你可以寫一個(gè)比較聰明的 SaferHTML 函數(shù),使其能實(shí)際上能解析在 templateData 里的字符串中的 HTML 塊。實(shí)現(xiàn)以后,它知道哪些替換是純 HTML; 哪些是內(nèi)部元素的屬性,需要轉(zhuǎn)義 ' 和 ” ;哪些是在 URL 查詢字符串,需要 URL 轉(zhuǎn)義而不是 HTML 轉(zhuǎn)義,等等。這可以只是為每個(gè)替換進(jìn)行轉(zhuǎn)義。

    因?yàn)?HTML 解析是很慢的,所以這聽起來有些牽強(qiáng)嗎?幸運(yùn)的是,一個(gè)標(biāo)簽?zāi)0宓淖址糠衷谀0姹恢匦略u估時(shí)是不改變的。SaferHTML 可以緩存所有分析的結(jié)果以加快之后調(diào)用。(緩存可能是一個(gè) WeakMap。這是 ES6 的另一個(gè)功能,我們將在以后的博客中進(jìn)行討論)。

  • 模板字符串沒有內(nèi)置的國際化功能。但通過使用標(biāo)簽,我們將他們添加進(jìn)去。Jack Hsu 的一個(gè)博客帖子展示了這個(gè)方法的第一個(gè)步驟可能是什么樣子的。僅舉一例:

      i18n\`Hello ${name}, you have ${amount}:c(CAD) in your bank account.`   
      // => Hallo Bob, Sie haben 1.234,56 $CA auf Ihrem Bankkonto.

    注意在這個(gè)例子中,name 和 amount 是屬于 JavaScript 的,但不熟悉的代碼有一個(gè)不同的位,即:c(CAD),在模板的字符串部分 Jack Hsu 所放的地方。JavaScript 是理所當(dāng)然由 JavaScript 引擎處理;字符串部分由 Jack Hsu 的 i18n 標(biāo)簽處理。用戶將從國際化文檔中學(xué)習(xí)到 :c(CAD) 指的是 amount 是用加元結(jié)算的貨幣的量。

    這就是標(biāo)簽?zāi)0逅龅墓ぷ鳌?/p>

  • 模板字符串是沒有替代 Mustache 和 Nunjucks,其部分原因是因?yàn)樗麄儧]有針對循環(huán)或條件的內(nèi)置語法。但是,現(xiàn)在我們已經(jīng)開始看到你將如何去解決這個(gè)問題了,對吧?如果 JS 在未來不提供該功能,那就寫一個(gè)標(biāo)簽以提供這種功能。

      // Purely hypothetical template language based on
      // ES6 tagged templates.
      var libraryHtml = hashTemplate`
       <ul>
          #for book in ${myBooks}
            <li><i>#{book.title}</i> by #{book.author}</li>
              #end
        </ul>
       `;

    靈活性并沒有就此止步。需要注意的是,標(biāo)簽函數(shù)的參數(shù)不會自動(dòng)轉(zhuǎn)換為字符串。他們可以是任何東西。這同樣適用于返回值。標(biāo)簽?zāi)0迳踔翛]有必然的字符串!你可以使用自定義的標(biāo)簽來創(chuàng)建正則表達(dá)式,DOM 樹,圖像,承諾代表整個(gè)異步進(jìn)程,JS 數(shù)據(jù)結(jié)構(gòu),GL 著色器等等。

    標(biāo)簽?zāi)0逖垘煸O(shè)計(jì)人員去創(chuàng)建強(qiáng)大的特定領(lǐng)域的語言。這些語言可能看起來一點(diǎn)也不像 JS ,但他們?nèi)匀豢梢郧度朐?JS 中,并與語言的其他部分無縫地智能地進(jìn)行交互。隨口說說,我想不出在任何其他語言有什么與他很類似的。我不知道這個(gè)功能將帶我們走多遠(yuǎn)。但是這種可能性是令人興奮的。

我什么時(shí)候才能開始使用?

在服務(wù)器中, io.js 是支持 ES6 模版字符串的。

在瀏覽器中,火狐瀏覽器 34 以上的版本是支持模版字符串的。他們是由 Guptha Rajagopal 在上個(gè)夏天作為一個(gè)實(shí)習(xí)項(xiàng)目完成的。谷歌瀏覽器41以上的版本也支持模版字符串,但是微軟瀏覽器 IE 和蘋果的瀏覽器 Safari 不支持。到現(xiàn)在為止,如果你想在網(wǎng)絡(luò)上使用模版字符串,你將需要使用Babel 或者 Traceur。你也可以在 TypeScript 中立即進(jìn)行使用。

等等——能不能在 Markdown 中使用?

嗯?

哦,很好的問題。

(這個(gè)章節(jié)不是真正關(guān)于 JavaScript 的。如果你不使用 Markdown,你可以跳過。)

對于模版字符串,Markdown 和 JavaScript 都使用 ` 字符來表明一些特殊性。事實(shí)上,在 Markdown 里,它是嵌入式文本中間的代碼片段的分隔符。

這帶來了點(diǎn)問題!如果你在 Markdown 文檔中寫這個(gè)字符串:

為了顯示一條消息,寫 ` alert(`世界你好!`)`。

它會顯示如下:

<a>為了顯示一條消息,寫 alert ( 世界你好!)。</a>

注意到,在輸出中是沒有反引號的。Markdown 將四個(gè)反引號都解釋為代碼分隔符并被 HTML 的標(biāo)簽取而代之。

為了防止這種現(xiàn)象,

我們轉(zhuǎn)向 Markdown 中從一開始就鮮為人知的功能:您可以使用多個(gè)反引號作為分隔符的代碼,就像這樣:

顯示一條消息,寫``alert( `世界你好!`)` `。

Gist 包含了更多的內(nèi)容,且其是在 Markdown 中編寫,所以你可以去看看。