Vue ソース コードの探索: 口ひげテンプレート エンジン (8) ネストトークンについて理解する 手書きカーディング テンプレート文字列ポンド記号ループネスト構造トークン

上記はVue ソース コードを調べています: 口ひげテンプレート エンジン (7) 手書きテンプレート文字列変換トークン配列のプロセスでは、比較的単純なトークン配列を操作し、ポンド記号とバックスラッシュの特殊記号構文を単純に処理しました。

したがって、分散したトークンをネストする必要があります。
これは、シャープ記号とバックスラッシュの間の内容が明らかにループ ステートメントのサブセットに属しているという事実に主に反映されていますが、現在は水平関係にあり、主な問題があり
ます
ここに画像の説明を挿入
。これは内部的なものです。複数のレベルのネストがある場合があります。
たとえば、ループ内でリサイクルします。

これを処理するとレイヤーごとのデータ構造になるので、「スタック」を思い浮かべる人も多いと思いますが、
これも聞いたことはあっても深く理解していない知識ですので、
まずはスタックの概念について説明しましょう。

まず、これは積み重ねの結果ですが、これは人生でよくあることです。たとえば、バドミントンのバケツは片方
しか開いていません。
ボールを入れたい場合は、1つずつしか入れることができません。この構造体を取り出すには、
ここに画像の説明を挿入
最後の構造体を取り出す必要があります。、取り出す順序は自然にこの順序になります。簡単に言うと、最初に呼び出されます。ラストアウトで。


コンセプトは、ポンド記号に遭遇した場合はそれをスタックにプッシュし、バックスラッシュに遭遇した場合はスタックからポップするというものです。

次に、アイデアが思いつきました。プロジェクトを開いて
src の下に nestTokens.js を作成しましょう。
ここに画像の説明を挿入
まず次のようなコードを記述します。

/*
    整合tokens  将#与/ 之前的内容  整合为 下标为三的元素
*/
export default function nestTokens(tokens) {
    
    

};

私たちのファイルは、トークンを処理する関数関数をスローするだけで
、シャープ記号の下のコンテンツをバックスラッシュの前のコンテンツに統合し、添え字が 3 の配列に統合します。

次に、formConversToken.js を開き、nestTokens をインポートして使用し、
ここに画像の説明を挿入
上記のトークン処理関数を導入して
、返されたときにデータを処理できるように関数に組み込みます。ただし、まだ記述していないため、
元のトークンは未定義になっています。何かの戻り値がない場合、これを実行しても当然何も得られません。
ここに画像の説明を挿入

そこで、ここではまず、nestTokens に変更し、受け取ったものを直接返します。
ここに画像の説明を挿入
トークンが再び出てきます
ここに画像の説明を挿入
。そして、アルゴリズムを書き始めます。もちろん、
アイデアをフィルタリングする限り、どのようなアルゴリズムも難しいものではありません。どうやって達成するのか

まず、nestTokens 関数をこれに変更しましょう

/*
    整合tokens  将#与/ 之前的内容  整合为 下标为三的元素
*/
export default function nestTokens(tokens) {
    
    
    //先定义一个数组 存储放回结果
    let nestedTokens = [];
    //做一个数组  来存栈中数据
    let sections = [];
    //循环遍历外面传进来的tokens
    for(let i = 0;i < tokens.length;i++) {
    
    
        //定义一个叫token的变量存储  当前循环遍历的下标
        let token = tokens[i];
        //判断下一当前循环的下标数组 第一个下标是不是 井号 或者 反斜杠  如果都不是 做另外处理
        switch(token[0]) {
    
    
            case '#':
                //如果是井号
                sections.push(token);
                console.log(token[1],"入栈啦");
                break;
            case '/':
                //如果是反斜杠
                let pot = sections.pop();
                console.log(pot[1],"出栈啦");
                break;
            default:
                //既不是井号  又不是反斜杠
        }
    }

    return nestedTokens;
};

まず、最後に返された結果を保存するためのnestedTokensを定義し
、次にスタッキングとポップのロジックを処理するためのセクション配列を定義し、
渡されたトークン配列をループして
から、現在のループの添字コンテンツを保存するトークンを定義しましょう。 traversal . 0 添字はポンド記号です。これは、スタックに
プッシュすることを意味します。コンテンツを追加するには、pushを使用します。バックスラッシュの場合は、pop を使用します。このメソッドについては、最後の添字を削除する方法について学ぶことができます。配列を取得して削除されたコンテンツを返し、値を受け取って出力を返します。


操作の結果は次のようになります。
ここに画像の説明を挿入
シャープ記号と一致した後、push によって内容を配列に追加し
、バックスラッシュが一致したときに、pop によって配列の最後の添字を削除します。

nestedToken は何も処理を行っていないため、戻り値は当然空の配列になります。

次に、コードをさらに次のように変更できます

/*
    整合tokens  将#与/ 之前的内容  整合为 下标为三的元素
*/
export default function nestTokens(tokens) {
    
    
    //先定义一个数组 存储放回结果
    let nestedTokens = [];
    //做一个数组  来存栈中数据
    let sections = [];
    //循环遍历外面传进来的tokens
    for(let i = 0;i < tokens.length;i++) {
    
    
        //定义一个叫token的变量存储  当前循环遍历的下标
        let token = tokens[i];
        //判断下一当前循环的下标数组 第一个下标是不是 井号 或者 反斜杠  如果都不是 做另外处理
        switch(token[0]) {
    
    
            case '#':
                //将当前遍历的元素的第二个下标定义为一个空数组  以便收集井号内的子元素
                token[2] = [];
                //如果是井号
                sections.push(token);
                break;
            case '/':
                //如果是反斜杠
                let pot = sections.pop();
                //将被删除的栈内容 加入到nestedTokens中
                nestedTokens.push(pot);
                break;
            default:
                //既不是井号  又不是反斜杠

                //判断sections储存栈内容数组 是否是空的
                if(sections.length == 0) {
    
    
                    //直接将当前下标装入结果数组
                    nestedTokens.push(token);
                } else {
    
    
                    //走进else  说明  sections  中是有内容的 当前正在入栈

                    //将当前遍历的下标内容  push进sections最后一个元素的  2下标下
                    sections[sections.length - 1][2].push(token);

                }
        }
    }

    return nestedTokens;
};

変更する重要なことは、デフォルトで現在走査されている添え字配列 0 がポンド記号でもバックスラッシュでもないことです。その場合、セクションにコンテンツがあるかどうかを判断します。セクションにコンテンツがある場合は、現在のサイクルが収集中であることを意味するためです。セクションが
空の場合 現在のコンテンツはポンド記号とバックスラッシュで囲まれておらず、nestedTokens に直接追加して第 1 レベルのデータにすることができます。それ以外の場合は、
現在のコンテンツを最後の添字の添字 2 に直接プッシュします。セクションの配列。前のケース '#' : シャープ記号の場合、2 の添え字が直接作成されると書かれています。デフォルト値は空の配列です。ここでは、コンテンツがこの空の配列にプッシュされます。

次に、もう 1 つの変更は、スタック ケース '/' です:
スタックをポップするときにプッシュすることで、セクションをnestedTokens 結果配列に追加します。
実行結果は次のとおりです。
ここに画像の説明を挿入
配列内のコンテンツが正常に収集されていることがわかります。シャープ記号とバックスラッシュの内容

しかし、これにはまだいくつか問題があるので、
www の下にあるindex.html をこれに変更します。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src = "/xuni/bundle.js"></script>
    <script>
        let templateStr = `
            <div>
                {
       
       {#students}}
                    <ul>
                        <li>{
       
       { item.name }}</li>
                        {
       
       {#item.list}}
                            <li>{
       
       { . }}</li>
                        {
       
       {/item.list}}
                    </ul>
                {
       
       {/students}}
            </div>
        `;
        let data = {
      
      
            name: "小猫猫",
            age: 2,
            students: [
                {
      
      
                    id: 0,
                    name: "小明",
                    list: [
                        "篮球",
                        "唱",
                        "跳"
                    ]
                },
                {
      
      
                    id: 1,
                    name: "小红",
                    list: [
                        "电子游戏",
                        "计算机编程"
                    ]
                }
            ]
        }
        GrManagData.render(templateStr,data);
    </script>
</body>
</html>

ここでは2段ネストしたスチューデントを最初にループするように変更し、そのループに対応する添字の下にリスト配列を記述しましたが、
演算結果は以下のようになります。2
ここに画像の説明を挿入
つのポンド記号がフラットな構造になっていることがわかります、しかし明らかに item.list は学生のサブセットであるべきです

Mustache.jsの公式の書き方がわかりますMustache.jsでnestTokensを検索するのが以下の機能内容です
ここに画像の説明を挿入
まずこの文章はjsのシャローコピーの構文を使っていますディープコピーとディープコピーの概念を学ぶことができます浅いコピーです。ここではそれを使用しています。参照型はこれに直接等しいので
、コレクタとnestedTokensが同じ記憶領域を指していることを意味します。
これらの2つの変数が同じ配列を指していることも理解できますが、次のことが
ここに画像の説明を挿入
わかります。このメソッドは実際には同じではありませんが、アイデアが貧弱です。特に大したことではありません。
実際、私たちの研究を使用してこの問題を解決できます。
私は皆にそれを自分で書いてもらっているだけです。そうすれば、これを直接書き直すことができますループステートメントを使用するか、公式の計画に従ってください。

ここで、nestToken をこれに直接変更します

/*
    整合tokens  将#与/ 之前的内容  整合为 下标为三的元素
*/
export default function nestTokens(tokens) {
    
    
    //先定义一个数组 存储放回结果
    let nestedTokens = [];
    //做一个数组  来存栈中数据
    let sections = [];
    //创建 collector 收集器  直接指向 nestedTokens 结果数组
    let collector = nestedTokens;

    //循环遍历外面传进来的tokens
    for(let i = 0;i < tokens.length;i++) {
    
    
        //定义一个叫token的变量存储  当前循环遍历的下标
        let token = tokens[i];
        //判断下一当前循环的下标数组 第一个下标是不是 井号 或者 反斜杠  如果都不是 做另外处理
        switch(token[0]) {
    
    
            case '#':
                //如果是井号
                //将当前元素  存入collector收集器
                collector.push(token);
                //当前元素入栈
                sections.push(token);
                //直接在用等于 让收集器collector指向 当前元素的2下标  顺手token[2] = [];  就是给token定义 2下标 默认值一个空数组
                collector = token[2] = [];
                break;
            case '/':
                //如果是反斜杠 出栈
                let pot = sections.pop();
                //判断  如果sections是空的  则等于nestedTokens结果数组  如果不是  就等于 sections最后一个下标的二下标
                collector = sections.length > 0?sections[sections.length - 1][2]:nestedTokens;
                break;
            default:
                //直接将内容放入收起器中
                collector.push(token);
        }
    }

    return nestedTokens;
};

この関数は、js のシャロー コピー配列やその他の参照型が直接イコールを使用してポインティングの原則を変更できるという原理を巧みに利用しています。
シャロー コピーのせいでコードにバグが発生する人も多いかもしれませんが、ここではシャロー コピーの良い使い方を紹介します。

まず第一に、最初にコレクターによって指定されたnestedTokensが結果の配列です。
その後、collector.pushは毎回nestedTokensを保存します。
シャープ記号に遭遇すると、毎回、collector.pushはプッシュされた最後の要素の2つの添え字を入力します。スタックに
挿入してから終了します。この判断はスタックするときにより重要です。
最後の要素が Pop によって強制終了された後もセクションにまだ要素がある場合、
それは以前に他のウェルの兆候と一致したことを意味し、ループが他のループに書かれていることを示します。
2 添字がなくなっている場合は、それが最後にあることを意味し
nestedTokens に戻ります。
ここに画像の説明を挿入
結果は非常に完璧であることがわかります。このアルゴリズムは、特に浅いコピーを正確に適用するために、非常に独創的であると言えます。
フレームワークを学習すれば、重要なポイントを覚えていただけると幸いです。これらのアルゴリズムなどの API の原理を学習すると正直、
これを丸暗記してしまうと時間を無駄にしてしまいます。

おすすめ

転載: blog.csdn.net/weixin_45966674/article/details/132039500