相关文章:san.js源码解读之模版解析(parseTemplate)篇——readIdent函数
一、源码分析
/**
 * 读取访问表达式
 *
 * @param {Walker} walker 源码读取对象
 * @return {Object}
 */
function readAccessor(walker) {
    var firstSeg = readIdent(walker);
    switch (firstSeg) { // 判断标识符
        case 'true':
        case 'false':
            return { // 遇到布尔值直接返回
                type: ExprType.BOOL,
                value: firstSeg === 'true', // 和字符串 'true' 直接判断返回布尔值
            };
        case 'null':
            return {
                type: ExprType.NULL
            };
    }
    var result = {
        type: ExprType.ACCESSOR, // 当前类型
        paths: [
            {type: ExprType.STRING, value: firstSeg}
        ]
    };
    /* eslint-disable no-constant-condition */
    // 对象访问有两种形式
    // 1: 点符号 - 在JavaScript中访问对象属性的一种常见方式是通过点符号。这涉及到在对象名称之后指定属性名称,两者之间用一个点隔开。
    // 例如:const name = {
    //   firstName: "Surbhi",
    //   lastName: "Dighe
    //  };
    // console.log(name.firstName);  // Output: "Surbhi"
    // 2: 括号符号 - 另一种访问对象属性的方法是通过括号符号,这涉及到将属性名称指定为方括号内的字符串
    // 例如:console.log(name["firstName"]);  // Output: "Surbhi"
    accessorLoop: while (1) {
    /* eslint-enable no-constant-condition */
        switch (walker.source.charCodeAt(walker.index)) {
            case 46: // .    当遇到 '.' 说明变量访问是 'person.job' 或者 'person[1].job' 之类的变量访问
                 walker.index++; // 向前移动,移过 '.'
                // ident as string
                // 因为遇到了 '.' 说明下面一定是一个变量名,所以使用 readIdent 进行解析
                result.paths.push({
                    type: ExprType.STRING,
                    value: readIdent(walker)
                });
                break;
            case 91: // [  当遇到 '[' 说明当前正处于 'person[]'
                walker.index++; // 向前移动,移过 '['
                result.paths.push(readTertiaryExpr(walker)); // 调用 readTertiaryExpr 进行匹配, 这是因为 '[]' 中可以有其他表达式,比如 'person[ index === 1 ? 1 : 0]' 或者 'person[name]'
                walker.goUntil(93); // ]
                break;
            default:
                break accessorLoop; // 默认跳出循环
        }
    }
    return result; // 返回匹配结果
}
在 javascript 中访问对象属性有两种方法分别如下
 1: 点符号 - 在JavaScript中访问对象属性的一种常见方式是通过点符号。这涉及到在对象名称之后指定属性名称,两者之间用一个点隔开。
 例如:
 		   const name = {
 		    firstName: "Surbhi",
 		    lastName: "Dighe
 		    };	
 	    	console.log(name.firstName);  // Output: "Surbhi"
2: 括号符号 - 另一种访问对象属性的方法是通过括号符号,这涉及到将属性名称指定为方括号内的字符串
 例如:
  console.log(name["firstName"]); // Output: "Surbhi" 
 在 readAccessor 中对属性访问的处理也是分这两种情况(但是需要了解的是‘person’单独变量在 readAccessor 函数中也是可以解析的,作为访问表达式,这也为什么readAccessor 函数的功能叫做读取访问表达式,而不是读取对象属性)。
首先通过 readIdent 函数解析出当前变量名,对变量名进行匹配如下
switch (firstSeg) { // 判断标识符
        case 'true':
        case 'false':
            return { // 遇到布尔值直接返回
                type: ExprType.BOOL,
                value: firstSeg === 'true', // 和字符串 'true' 直接判断返回布尔值
            };
        case 'null':
            return {
                type: ExprType.NULL
            };
    }
如果符合 ‘true’ 、‘false’和’null’,那么直接返回,后续不执行。那么什么时候遇到这种情况呐?比如 三元表达式时,匹配到‘true’或者‘false’就会走入该条件判断。
接着定义了访问符类型, 并且记录当前位置(value)
var result = {
      type: ExprType.ACCESSOR, // 当前类型
      paths: [
          {type: ExprType.STRING, value: firstSeg}
      ]
  };
然后对当前访问表达式进行循环匹配,当遇到 ‘.’ 时,说明是‘demo.job’ 这种情况,那么执行下面语句
case 46: // .    当遇到 '.' 说明变量访问是 'person.job' 或者 'person[1].job' 之类的变量访问
   walker.index++; // 向前移动,移过 '.'
   // ident as string
   // 因为遇到了 '.' 说明下面一定是一个变量名,所以使用 readIdent 进行解析
   result.paths.push({
       type: ExprType.STRING,
       value: readIdent(walker)
   });
   break;
当遇到‘[’时,说明是’demo[job]'、‘demo[index ? 1: 0]’ 、‘demo[‘true’]’等情况,那么执行面的语句
case 91: // [  当遇到 '[' 说明当前正处于 'person[]'
     walker.index++; // 向前移动,移过 '['
     result.paths.push(readTertiaryExpr(walker)); // 调用 readTertiaryExpr 进行匹配, 这是因为 '[]' 中可以有其他表达式,比如 'person[ index === 1 ? 1 : 0]' 或者 'person[name]'
     walker.goUntil(93); // ]
     break;
这里需要了解的是向 paths 数组中推入数据时调用了 readTertiaryExpr ,这是因为在‘[]’中可能有复杂的表达式,里面有变量数值等逻辑,所以需要从头解析。对于 readTertiaryExpr 函数内容后续会有介绍(解析表达式有点复杂,而且牵涉到嵌套、递归、解析先后顺序等逻辑)
当没有遇到‘.’或者‘[’, 那么走默认逻辑,直接跳出循环
default:
   break accessorLoop; // 默认跳出循环
二、示例: ‘person.job.one’
解析 ‘person.job.one’ 的结果
 



















