Heim  >  Artikel  >  Web-Frontend  >  Detaillierte Erläuterung der Vorlagenzeichenfolgen in JavaScript ES6_Grundkenntnisse

Detaillierte Erläuterung der Vorlagenzeichenfolgen in JavaScript ES6_Grundkenntnisse

WBOY
WBOYOriginal
2016-05-16 15:48:411436Durchsuche

In ES6 wird ein neuer Typ von String-Literal eingeführt – Vorlagen-Strings. Bis auf die Verwendung von Backticks (`) sehen sie genauso aus wie gewöhnliche Strings. Im einfachsten Fall handelt es sich lediglich um gewöhnliche Zeichenfolgen:

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

wird als Vorlagenzeichenfolge bezeichnet, da die Vorlagenzeichenfolge eine einfache Zeichenfolgeninterpolationsfunktion in JS einführt, d. h. der JS-Wert kann bequem und elegant in eine Zeichenfolge eingefügt werden.

Vorlagenzeichenfolgen können an vielen Stellen verwendet werden. Sehen Sie sich die folgende unauffällige Fehlermeldung an:

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}.`);
 }
}

Im obigen Code werden ${user.name} und ${action} als Vorlagenplatzhalter bezeichnet. JavaScript fügt die Werte von user.name bzw. action an den entsprechenden Positionen ein und generiert dann „User „So ist Jorendorff nicht berechtigt, Eishockey zu spielen.“

Da wir nun eine elegantere Syntax als der Operator haben, sind hier einige Funktionen, die Sie erwarten können:

Der Vorlagenplatzhalter kann ein beliebiger JavaScript-Ausdruck sein, daher sind Funktionsaufrufe und vier arithmetische Operationen zulässig. (Sie können eine Vorlagenzeichenfolge sogar in einer anderen Vorlagenzeichenfolge verschachteln.)
Wenn ein Wert kein String ist, wird er in einen String umgewandelt. Wenn es sich bei der Aktion beispielsweise um ein Objekt handelt, wird .toString() dieses Objekts aufgerufen, um es in einen String umzuwandeln.
Wenn Sie Backticks in einer Vorlagenzeichenfolge verwenden möchten, müssen Sie diese mit einem Backslash maskieren.
Wenn Sie ${ in der Vorlagenzeichenfolge ausgeben möchten, müssen Sie ebenfalls Backslashes verwenden, um es zu maskieren: ${ oder ${.
Vorlagenzeichenfolgen können sich über mehrere Zeilen erstrecken:

$("#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>
`);

Alle Leerzeichen, Zeilenumbrüche und Einzüge in der Vorlagenzeichenfolge werden unverändert in die Ergebniszeichenfolge ausgegeben.

Werfen wir einen Blick darauf, was Vorlagenzeichenfolgen nicht können:

Sonderzeichen werden nicht automatisch maskiert, um Cross-Site-Scripting-Schwachstellen zu vermeiden. Sie müssen dennoch mit nicht vertrauenswürdigen Daten vorsichtig sein, genau wie mit gewöhnlichen Zeichenfolgen.
Es kann nicht mit internationalen Bibliotheken verwendet werden und verarbeitet keine Zahlen, Datumsangaben usw. in speziellen Sprachformaten.
Kein Ersatz für Template-Engines (wie Mustache oder Nunjucks). Vorlagenzeichenfolgen haben keine Syntax für die Verarbeitung von Schleifen – Sie können keine Tabelle aus einem Array erstellen.

Um diese Einschränkungen zu beheben, stellt ES6 Entwicklern und Bibliotheksdesignern eine andere Art von Vorlagenzeichenfolge zur Verfügung – Tag-Vorlagen.

Die Syntax der

-Tag-Vorlage ist sehr einfach. Sie müssen lediglich vor dem Start-Backtick ein Tag einfügen. Schauen wir uns das erste Beispiel an: SaferHTML. Wir werden diese Tag-Vorlage verwenden, um die erste oben erwähnte Einschränkung zu lösen: automatisches Escapen von Sonderzeichen.

Es ist zu beachten, dass die SaferHTML-Methode nicht von der ES6-Standardbibliothek bereitgestellt wird, wir müssen sie selbst implementieren:

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

Das SaferHTML-Tag ist hier ein einzelner Bezeichner, und das Tag kann auch ein Attribut sein, wie z. B. SaferHTML.escape, oder sogar ein Methodenaufruf: SaferHTML.escape({unicodeControlCharacters: false}). Genauer gesagt kann jeder ES6-Mitgliedsausdruck oder Aufrufausdruck als Tag verwendet werden.

Es ist ersichtlich, dass die Vorlagenzeichenfolge nur syntaktischer Zucker für die Zeichenfolgenverkettung ist, während die Etikettenvorlage tatsächlich etwas völlig anderes ist: ein Funktionsaufruf.

Der obige Code entspricht also:

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

Dabei ist templateData ein unveränderliches String-Array, das von der JS-Engine basierend auf dem Quell-Template-String generiert wird. Das Array enthält hier zwei Elemente, da der Template-String zwei Strings enthält, nachdem er durch Platzhalter getrennt wurde : Object.freeze(["e388a4556c0f65e1904146cc1a846bee", " hat dir einen Bonk geschickt.94b3e26ee717c64999d7867364b1b4a3"]

(Tatsächlich gibt es ein weiteres Attribut für templateData: templateData.raw. In diesem Artikel wird dieses Attribut nicht ausführlich behandelt. Der Wert dieses Attributs ist ebenfalls ein Array, einschließlich aller Zeichenfolgenteile in der Tag-Vorlage, aber die string Enthält Escape-Sequenzen, die eher wie Zeichenfolgen im Quellcode aussehen, z. B. n. Das in ES6 integrierte Tag String.raw verwendet diese Zeichenfolgen.

Dadurch kann die SaferHTML-Methode diese beiden Zeichenfolgen nach Belieben analysieren, und es gibt N Ersetzungsmethoden.

Während Sie weiterlesen, fragen Sie sich möglicherweise, wie Sie die SaferHTML-Methode implementieren.

Hier ist eine Implementierung (Kerninhalt):

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 中,并且可以与语言的其余部分进行交互。顺便说一下,我还没有在其他语言中见过类似的特性,我不知道这个特性讲给我们带来些什么,但各种可能性还是非常令人兴奋的。

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn