This article continues with the study notes for Mustache with two pieces of Mustache Engine 01 and Mustache Engine 02

In the previous notes, we have successfully implemented the process of compiling the template string into Tokens, and the rest of the work is to parse tokens and data into DOM strings. That is the red box in the following image

Tokens combine data to parse into DOM strings

The general idea is to iterate through the array of tokens, and do different processing according to the value of the first item of each token. For text, the token[1] is directly added to the final output of the DOM string. For name, the token[1] is used to obtain data from the data and combine it.

Data = {test: {a: {b: If the token is [“name”, “test.a.b”], then the second element of the token is a value with multiple dot symbols such as test.a.b. We can’t get the correct value from data[test.a.b] because js doesn’t know how to write it. We need to prepare a lookup function in advance to get the data correctly.

Defining the Lookup function

// lookup.js
// Select test.a from test.a and temp from test. b
export default (data, key) => {
  // If the key is passed in with dots and not just dots
  if (key.indexOf('. ')! = = -1&& key ! = ='. ' ) {
    const keys = key.split('. ') // Split the key into an array with
    return keys.reduce((acc, cur) = > {
      return acc[cur] // Step by step
    }, data)
  // If a key is passed without a dot, return it
  return data[key]
Copy the code

Define the renderTemplate function

Next, you can write a renderTemplate function that passes tokens and data as parameters and parses them into dom strings.

// renderTemplate.js
import lookup from './lookup.js'
import parseArray from './parseArray.js'

export default (tokens, data) => {
  let domString = ' '
  tokens.forEach(token= > {  
    switch (token[0]) {
      case 'text':
        domString += token[1]
      case 'name':
        domString += lookup(data, token[1])
      case The '#':
        domString += parseArray(token[2], data[token[1]])
        break}})return domString
Copy the code

Note that in the case of a loop, renderTemplate is recursively called again when the first item of a token is “#”. Here we define a new parseArray function to do that.

// parseArray.js
import renderTemplate from './renderTemplate.js'
export default (tokens, data) => {
  let domString = ' '
  data.forEach(itemData= >{ domString += renderTemplate(tokens, { ... itemData,'. ': itemData // In the case of simple arrays, i.e. {{.}} in the template string})})return domString
Copy the code

This concludes this series of notes. Ability is general, level is limited, it is inevitable that there will be flaws and deficiencies, also please judge the officials.

One More Thing

Here is a solution to the problem of continuous equal assignment raised at the end of the last part

let a = {n:1};
a.x = a = {n:2};
console.log(a.x); / / output?
Copy the code

The key reason why a.x is undefined is that “.” And “=” operator appears at the same time, the first execution “, “operation, so a.x = a = {2} n: this step is to give a first adds a property x, and at this point a or point to the object {n: 1}. That is, the original {n:1} object is now {n:1, x:a}, after which a is reassigned to the {n:2} object, so {n:1, x:a} has no variable reference collected by GC. Therefore, the value of a.x is undefined.