Angularjs 1.3 中的$parse实例代码(3)

在解析三目运算之前,又根据?将表达式划分成left和right两块。左侧再去尝试执行logicalOR,实际上这是一个逻辑与的解析,按照这个执行流程,我们一下有了思路。这有点类似我们一般写三目时。代码的执行情况,比如: 2 > 2 ? 1 : 0。如果把这个当成表达式,那根据?划分left和right,left就应该是2 > 2,right应该就是 1: 0。然后尝试在left看是否有逻辑或的操作。也就是,Parser里面的方法调用的嵌套级数越深,其方法的优先级则越高。好,那我们一口气看看这个最高的优先级在哪?

logicalOR -> logicalAND -> equality -> relational -> additive -> multiplicative -> unary

好吧,嵌套级数确实有点多。那么我们看下unary。

unary: function() { var token; if (this.expect('+')) { return this.primary(); } else if ((token = this.expect('-'))) { return this.binaryFn(Parser.ZERO, token.text, this.unary()); } else if ((token = this.expect('!'))) { return this.unaryFn(token.text, this.unary()); } else { return this.primary(); } }

这边需要看两个主要的方法,一个是binaryFn和primay。如果判断是-,则必须通过binaryFn去添加函数。看下binaryFn

binaryFn: function(left, op, right, isBranching) { var fn = OPERATORS[op]; return extend(function $parseBinaryFn(self, locals) { return fn(self, locals, left, right); }, { constant: left.constant && right.constant, inputs: !isBranching && [left, right] }); }

其中OPERATORS是之前聊Lexer也用到过,它根据操作符存储相应的操作函数。看一下fn(self, locals, left, right)。而我们随便取OPERATORS中的一个例子:

'-':function(self, locals, a, b) { a=a(self, locals); b=b(self, locals); return (isDefined(a) ? a : 0) - (isDefined(b) ? b : 0); }

其中a和b就是left和right,他们其实都是返回的跟之前类似的$parseStatements方法。默认存储着token中的value。经过事先解析好的四则运算来生成最终答案。其实这就是Parser的基本功能。至于嵌套,我们可以把它理解为js的操作符的优先级。这样就一目了然了。至于primay方法。塔刷选{ ( 对象做进一步的解析过程。

Parser的代码并不复杂,只是函数方法间调用密切,让我们再看一个例子:

var _l = new Lexer({}); var _p = new Parser(_l); var a = _p.parse("1 + 1 + 2"); console.log(a()); //4

我们看下1+1+2生成的token是什么样的:

[ {"index":0,"text":"1","constant":true,"value":1},{"index":2,"text":"+","operator":true},{"index":4,"text":"1","constant":true,"value":1},{"index":6,"text":"+","operator":true},{"index":8,"text":"2","constant":true,"value":2} ]

Parser根据lexer生成的tokens尝试解析。tokens每一个成员都会生成一个函数,其先后执行逻辑按照用户输入的1+1+2的顺序执行。注意像1和2这类constants为true的token,parser会通过constant生成需要的函数$parseConstant,也就是说1+1+2中的两个1和一个2都是返回$parseConstant函数,通过$parseBinaryFn管理加法逻辑。

constant: function() { var value = this.consume().value; return extend(function $parseConstant() { return value; //这个函数执行之后,就是将value值返回。 }, { constant: true, literal: true }); }, binaryFn: function(left, op, right, isBranching) { var fn = OPERATORS[op];//加法逻辑 return extend(function $parseBinaryFn(self, locals) { return fn(self, locals, left, right);//left和right分别表示生成的对应函数 }, { constant: left.constant && right.constant, inputs: !isBranching && [left, right] }); }

那我们demo中的a应该返回什么函数呢?当然是$parseBinaryFn。其中的left和right分别是1+1的$parseBinaryFn,right就是2的$parseConstant。

再来一个例子:

var _l = new Lexer({}); var _p = new Parser(_l); var a = _p.parse('{"name": "hello"}'); console.log(a);

这边我们传入一个json,理论上我们执行完a函数,应该返回一个{name: "hello"}的对象。它调用了Parser中的object

object: function() { var keys = [], valueFns = []; if (this.peekToken().text !== '}') { do { if (this.peek('}')) { // Support trailing commas per ES5.1. break; } var token = this.consume(); if (token.constant) { //把key取出来 keys.push(token.value); } else if (token.identifier) { keys.push(token.text); } else { this.throwError("invalid key", token); } this.consume(':'); //冒号之后,则是值,将值存在valueFns中 valueFns.push(this.expression()); //根据逗号去迭代下一个 } while (this.expect(',')); } this.consume('}'); return extend(function $parseObjectLiteral(self, locals) { var object = {}; for (var i = 0, ii = valueFns.length; i < ii; i++) { object[keys[i]] = valueFns[i](self, locals); } return object; }, { literal: true, constant: valueFns.every(isConstant), inputs: valueFns }); }

比方我们的例子{"name": "hello"},object会将name存在keys中,hello则会生成$parseConstant函数存在valueFns中,最终返回$parseObjectLiternal函数。

下一个例子:

var a = _p.parse('{"name": "hello"}["name"]');

这个跟上一个例子的差别在于后面尝试去读取name的值,这边则调用parser中的objectIndex方法。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wygydw.html