ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript ES6のテンプレート文字列を詳しく解説_基礎知識

JavaScript ES6のテンプレート文字列を詳しく解説_基礎知識

WBOY
WBOYオリジナル
2016-05-16 15:48:411436ブラウズ

ES6 では、新しいタイプの文字列リテラルであるテンプレート文字列が導入されており、バックティック (`) の使用を除いて、通常の文字列と同じように見えます。最も単純なケースでは、これらは単なる普通の文字列です:

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

は、テンプレート文字列と呼ばれます。これは、テンプレート文字列が JS に単純な文字列補間機能を導入するためです。つまり、JS 値を文字列に便利かつエレガントに挿入できます。

テンプレート文字列はさまざまな場所で使用できます。次の目立たないエラー メッセージを見てください:

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

上記のコードでは、${user.name} と ${action} はテンプレート プレースホルダーと呼ばれ、JavaScript は user.name と action の値をそれぞれ対応する位置に挿入し、「User」を生成します。 「このように、ヨレンドルフにはホッケーをする権限がありません。」

演算子よりも洗練された構文ができたので、期待できる機能をいくつか紹介します。

テンプレートのプレースホルダーには任意の JavaScript 式を使用できるため、関数呼び出しと四則演算は正当です。 (テンプレート文字列を別のテンプレート文字列内にネストすることもできます。)
値が文字列でない場合は、文字列に変換されます。たとえば、アクションがオブジェクトの場合、そのオブジェクトの .toString() が呼び出されて文字列に変換されます。
テンプレート文字列でバッククォートを使用する場合は、バッククォートをバックスラッシュでエスケープする必要があります。
同様に、テンプレート文字列で ${ を出力する場合は、バックスラッシュを使用してエスケープする必要もあります (${ または ${)。
テンプレート文字列は複数行にまたがることができます:

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

テンプレート文字列内のすべてのスペース、改行、インデントがそのまま結果文字列に出力されます。

テンプレート文字列でできないことを見てみましょう:

特殊文字は自動的にエスケープされません。クロスサイト スクリプティングの脆弱性を回避するには、通常の文字列と同様に、信頼できないデータにも注意する必要があります。
国際ライブラリでは使用できず、特殊な言語形式の数値や日付などは処理されません。
テンプレート エンジン (MustacheNunjucks など) の代替ではありません。テンプレート文字列にはループを処理するための構文がありません。配列からテーブルを構築することはできません。

これらの制限に対処するために、ES6 は開発者とライブラリ設計者に別のタイプのテンプレート文字列であるタグ テンプレートを提供します。

タグ テンプレートの構文は非常に簡単で、開始バッククォートの前にタグを導入するだけで済みます。最初の例: SaferHTML を見ると、このタグ テンプレートを使用して、前述の最初の制限である特殊文字の自動エスケープを解決します。

SaferHTML メソッドは ES6 標準ライブラリでは提供されていないため、自分で実装する必要があることに注意してください:

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

ここでの SaferHTML タグは単一の識別子であり、タグは SaferHTML.escape などの属性、またはメソッド呼び出し SaferHTML.escape({unicodeControlCharacters: false}) であることもあります。正確には、任意の ES6 メンバー式または呼び出し式をタグとして使用できます。

テンプレート文字列は単なる文字列連結の糖衣構文であるのに対し、ラベル テンプレートはまったく別のもの、つまり関数呼び出しであることがわかります。

したがって、上記のコードは次と同等です:

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

ここで、templateData はソース テンプレート文字列に基づいて JS エンジンによって生成された不変の文字列配列です。テンプレート文字列にはプレースホルダーで区切られた 2 つの文字列が含まれるため、この配列には 2 つの要素が含まれます。 : Object.freeze(["e388a4556c0f65e1904146cc1a846bee", " はあなたにひどいことを送りました。94b3e26ee717c64999d7867364b1b4a3"]

(実際、templateData には別の属性 templateData.raw があります。この記事では、この属性については詳しく説明しません。この属性の値も配列であり、タグ テンプレート内のすべての文字列部分が含まれますが、 string ES6 の組み込みタグ String.raw は、これらの文字列 )

を使用します。

これにより、SaferHTML メソッドはこれら 2 つの文字列を自由に解析できるようになり、N 個の置換メソッドが存在します。

読み続けると、SaferHTML メソッドを実装する方法が疑問に思うかもしれません。

実装 (要点) は次のとおりです:

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, "&")
      .replace(/</g, "<")
      .replace(/>/g, ">");

  // Don't escape special characters in the template.
  s += templateData[i];
 }
 return s;
}
 
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, "&")
      .replace(/</g, "<")
      .replace(/>/g, ">");
 
  // Don't escape special characters in the template.
  s += templateData[i];
 }
 return s;
}

有了上面的方法,即使使用一个恶意的用户名,用户也是安全的。

一个简单的例子并不足以说明标签模板的灵活性,让我们重温一下上面列举的模板字符串的限制,看看我们还可以做些什么。

    模板字符串不会自动转义特殊字符,但是我们可以通过标签模板来解决这个问题,事实上我们还可以将 SaferHTML 这个方法写的更好。从安全角度来看,这个 SaferHTML 非常脆弱。在 HTML 中,不同的地方需要用不同的方式去转义,SaferHTML 并没有做到。稍加思考,我们就可以实现一个更加灵活的 SaferHTML方法,能够将 templateData 中的任何一个 HTML 转义,知道哪个占位符是纯 HTML;哪个是元素的属性,从而需要对 ' 和 " 转义;哪个是 URL 的 query 字符串,从而需要用 URL 的 escaping 方法,而不是 HTML 的 escaping;等等。这似乎有些牵强,因为 HTML 转义效率比较低。辛运是的,标签模板的字符串是保持不变的,SaferHTML 可以缓存已经转义过的字符串,从而提高效率。
    模板字符串并没有内置的国际化特性,但通过标签模板,我们可以添加该特性。Jack Hsu 的文章详细介绍了实现过程,看下面例子:

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




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

上面例子中的 name 和 amount 很好理解,将被 JS 引擎替换为对应的字符串,但是还有一个没有见过的占位符::c(CAD),这将被 i18n 标签处理,从 i18n 的文档可知::c(CAD)表示 amount 是加拿大美元货币值。

    模板字符串不能替代 Mustache 和 Nunjucks 这类模板引擎,部分原因在于模板字符串不支持循环和条件语句。我们可以编写一个标签来实现这类功能:

// 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>
`;

 
// 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>
`;

灵活性还不止于此,需要注意的是,标签函数的参数不会自动转换为字符串,参数可以是任何类型,返回值也一样。标签模板甚至可以不需要字符串,你可以使用自定义标签来创建正则表达式、DOM 树、图片、代表整个异步进程的 Promise、JS 数据结构、GL 着色器…

标签模板允许库设计者创建强大的领域特定语言。这些语言可能看上去并不像 JS,但他们可以无缝嵌入到 JS 中,并且可以与语言的其余部分进行交互。顺便说一下,我还没有在其他语言中见过类似的特性,我不知道这个特性讲给我们带来些什么,但各种可能性还是非常令人兴奋的。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。