メインコンテンツへ移動

テンプレート文字列_ES6 ノート 3

無料2016-04-10#JS#JS模板字符串#JS反撇号#JS标签模板#template string#template inception#tagged template

ES6 で最もオープンな特性で、文字列の連結だけでなく、もっと複雑なことができます

一.作用及び構文

テンプレート文字列は文字列の挿入を実現するために使用され、プラス記号(+)での連結よりも便利でエレガントです

`${expr}` 構文は、文字列挿入機能を提供します

注意:上記の`(バッククォート、キーボードの Esc の下にあります)はテンプレート文字列構文の一部であり、markdown の誤りではありません

P.S.筆者は最初の問題に遭遇しました。バッククォートと markdown 構文が衝突します。2 つの選択があります。markdown 特性の多重バッククォートをコード区切り文字として使用する(2 つの連続バッククォートでコードを囲むが、筆者が使用する markdown プラグインはこの珍しい構文をサポートしていない)、または code タグを使用する。例えば上記の markdown ソースコードは<code>\`${expr}\`</code> です

例えば:

function req(user, action) {
    // if !isValid
    error(`user ${user} failed to do action ${action}`);
}
function error(str) {
    console.log(str);
}
// test
req('Sam', 'login');    // user Sam failed to do action login

二.特徴

###1.expr は任意の合法 js 式でよく、ネストもサポート

変数、リテラル、関数呼び出しなどを含みますが、フロー制御(分岐/ループ)はサポートしないため、テンプレート文字列はテンプレートエンジンを代替できません

例えば:

// 不支持分支/循环
// console.log(`${if (2 > 1) {str}}`);  // Uncaught SyntaxError: Unexpected token if
// console.log(`${for (; false;) {}}`); // Uncaught SyntaxError: Unexpected token for

var outer = 'outer';
var inner = 'inner';
var str = `
\$\{
    ${
        outer   // 变量
        +       // + 拼接
        `\$\{
            ${inner}    // 插值
        \}`
    }
\}
`;

var h5 = document.querySelector('#h5');
var pre = document.querySelector('#pre');
h5.innerHTML = str;
pre.innerHTML = str;

表示結果は以下の通り:

// #h5
${ outer${ inner // 插值 } }
// #pre
${
    outer${
            inner    // 插值
        }
}

###3.複数行に分割して記述可能

ただし注釈(単行/多行)は文字列全体に作用するか、または結果文字列内にリテラルとして現れる可能性があります。テンプレート文字列中のすべてのスペース、改行、インデントは、生成された文字列中にそのまま出力されます(pre は他の要素と異なります)。具体的には上記の例を参照

###4.特殊文字はエスケープが必要

3 つの特殊文字[`${](正規表現形式)はエスケープが必要です。具体的には上記の例を参照

P.S.右中括弧はエスケープ不要ですが、もちろんエスケープしても間違いではありません。しかし上記 3 つは必須でエスケープする必要があります

###5.自動処理なし

安全でないタグを自動フィルタリングせず、特殊文字を自動エスケープもしません。xss 攻撃も防止する必要があります。タグテンプレート(tagged templates)を提供していますが、あまり便利ではありません

例えば:

// xss 攻击
var userInput = '<a href="" onclick="alert(\'xss attack\');">领取奖励</a>';
var input = document.querySelector('#input');
input.innerHTML = `用户输入:${userInput}`;

上記コードはリンクを生成し、クリックすると "xss attack" を alert します。タグテンプレートを通じてテンプレート文字列をカスタム処理できます。例えば安全でない文字をフィルタリング:

// 定义模板标签
function myFilter(templateData) {
    var aStr = templateData;        // 被${}插值分割后的字符串数组
    var aRaw = templateData.raw;    // 未经转义的原字符串(\n)
    var aVar = Array.prototype.slice.call(arguments, 1);    // 插值变量数组
    console.log(aStr);
    console.log(aRaw);
    console.log(aVar);

    // filter vars
    aVar.forEach(function(item, index, arr) {
        arr[index] = item.replace(/(<[^>]*>)/i, '');
    });
    var res = '';
    var i = 0;
    aStr.forEach(function(item) {
        res += item;
        if (aVar[i]) {
            res += aVar[i++];
        }
    });

    return res;
}

// 使用标签模板
var safeInput = document.querySelector('#safe_input');
safeInput.innerHTML = myFilter`用户输入:\n${userInput}`;
// 等价于
// safeInput.innerHTML = myFilter(['用户输入:'], userInput);

タグはテンプレート文字列の前に現れ、簡略化された関数呼び出し の一種です。テンプレートタグはコールバック関数に類似し、パラメータ templateData の形式は確定しており、パラメータからデータを取り出し、処理完了後に返すだけです

しかしテンプレートタグを定義するのはまだ面倒に感じられますが、これは非常に魅力的な特性で、強力な文字列処理ライブラリ(特殊文字のエスケープ、i18n、文字数統計など)を予感させます

###6.柔軟性

タグテンプレートの戻り値は文字列である必要はなく、任意の値 で構いません。これは単に強力な「文字列」処理ライブラリが現れるだけでなく、あらゆるライブラリがこの形式で完璧に JS 内に埋め込む ことができることを意味し、特にシェーダー言語のような現在 JS 内で形式があまり友好的でないもの……他の言語で魅力的な特性が現れた後、完璧に JS に移植でき、さらには借此で独自の言語を実装することもできます(テンプレートタグの関数本体がインタプリタです)

タグテンプレートは大きな柔軟性をもたらし、カスタムタグを使用して正規表現、DOM ツリー、画像、promises を代表とする非同期プロセス全体、JS データ構造、GL シェーダーなどを作成できます……

参考資料中の原文を引用:

标签模板以开放的姿态欢迎库设计者们来创建强有力领域特定语言。这些语言可能看起来不像 JS,但是它们仍可以无缝嵌入到 JS 中并与 JS 的其它语言特性智能交互。我不知道这一特性将会带领们走向何方,但它蕴藏着无限的可能性,这令我感到异常兴奋!

三.まとめ

テンプレート文字列は一見構文糖ですが、実は扉を開けたのであり、JS がオープンな姿勢で未来を迎えることを示しています

[先輩たちが 5 年前に議論した yield](/articles/javascript 实现 yield/) を覚えていますか?当時彼らはこのような特性をどれだけ望んでいたでしょうか。この問題を議論した初衷は JS が C# の yield 特性を獲得することを望んでいたからではありませんか?

参考資料

  • 《ES6 in Depth》:InfoQ 中文站提供的免费电子书

コメント

コメントはまだありません

コメントを書く