san.js源码解读之模版解析(parseTemplate)篇——readCall函数
相关文章 san.js源码解读之模版解析(parseTemplate)篇——readAccessor函数
一、源码分析
/**
* 读取调用
*
* @param {Walker} walker 源码读取对象
* @param {Array=} defaultArgs 默认参数
* @return {Object}
*/
function readCall(walker, defaultArgs) {
walker.goUntil(); // 向前读取字符,直到遇到指定字符再停止
var result = readAccessor(walker); // 读取访问表达式
var args;
if (walker.goUntil(40)) { // ( 判断是否遇到 '(', 如果遇到进入下面处理
args = [];
while (!walker.goUntil(41)) { // ) 判断是否遇到')',它是跳出循环的判断条件
args.push(readTertiaryExpr(walker)); // 因为在处理函数调用时,会遇到复杂的表达式,所以调用 readTertiaryExpr 函数来处理出现所以表达式的可能
walker.goUntil(44); // ,
}
}
else if (defaultArgs) {
args = defaultArgs; // 如果有默认参数时,直接赋值 args。这里比较好理解,因为上面的操作就是解析函数参数的。
}
if (args) {
result = {
type: ExprType.CALL,
name: result, // 把之前解析到的访问表达式,放入对象中并起名 name
args: args
};
}
return result; // 返回结果
}
在 san.js 中 readCall 函数是用来解析函数调用的。比如
<p>{{max(num1, num2)}}</p>
readCall 函数接收两个参数:walker 和 defaultArgs。
- walker 是 Walk 类的实例,它是源码读取对象
- defaultArgs 是默认参数,就是调用函数是传入的参数。比如 max(num1, num2) 中的 ’num1‘ 和 ‘num2’
当执行 readCall 函数时,首先执行 goUntil() 函数用来跳过空格、制表符、\r、\n之类的。goUntil 函数源码如下
/**
* 向前读取字符,直到遇到指定字符再停止
* 未指定字符时,当遇到第一个非空格、制表符的字符停止
*
* @param {number=} charCode 指定字符的code
* @return {boolean} 当指定字符时,返回是否碰到指定的字符
*/
Walker.prototype.goUntil = function (charCode) {
var code;
while (this.index < this.len && (code = this.source.charCodeAt(this.index))) {
switch (code) {
case 32: // 空格 space
case 9: // 制表符 tab
case 13: // \r
case 10: // \n
this.index++;
break;
default:
if (code === charCode) {
this.index++;
return 1;
}
return;
}
}
};
可以看出 goUntil 接受一个变量 charCode, 当传入该变量时或判断当前字符是否为传入的字符,如果时就返回 1并跳出循环,否者跳出循环。
接着调用 readAccessor 函数获取当前访问表达式并返回结果,然后向下面判断是否遇到‘(’,如果遇到就开始匹配括号内的参数,代码如下
if (walker.goUntil(40)) { // ( 判断是否遇到 '(', 如果遇到进入下面处理
args = [];
while (!walker.goUntil(41)) { // ) 判断是否遇到')',它是跳出循环的判断条件
args.push(readTertiaryExpr(walker)); // 因为在处理函数调用时,会遇到复杂的表达式,所以调用 readTertiaryExpr 函数来处理出现所以表达式的可能
walker.goUntil(44); // ,
}
}
如果没有遇到,接着判断有没有传入默认参数,有的话就直接把默认参数赋值给 args,最后返回属于调用函数类型的对象结果