Browse Source

new: explain some variables

HcySunYang 7 years ago
parent
commit
c6412f943a
1 changed files with 49 additions and 4 deletions
  1. 49 4
      docs/art/82vue-parsing.md

+ 49 - 4
docs/art/82vue-parsing.md

@@ -2808,7 +2808,7 @@ if (dynamicValue != null) {
 <div :key="/id|featId/.test(id).toString()"></div>  <!-- 正则表达式内的管道符 -->
 ```
 
-这种情况会比较复杂,因为我们要有能力识别出管道符是否存在于正则表达中才行,难点在就于如何识别正则表达式,我们知道正则表达式的由斜杠(`/`)开头,并以斜杠(`/`)结尾,但不要忘了斜杠在 `js` 这门语言中还被用作除法运算符。所以归根结底难点在于我们需要识别一个斜杠它所代表的意义到底是除法还是正则。
+这种情况会比较复杂,因为我们要有能力识别出管道符是否存在于正则表达中才行,难点在就于如何识别正则表达式,我们知道正则表达式的由斜杠(`/`)开头,并以斜杠(`/`)结尾,但不要忘了斜杠在 `js` 这门语言中还被用作除法运算符。所以归根结底难点在于我们需要识别一个斜杠它所代表的意义到底是除法还是正则。
 
 实际上这是一个相当复杂的事情,引用 [ECMA 规范](http://www.ecma-international.org/ecma-262/9.0/index.html#sec-ecmascript-language-lexical-grammar) 中的一段例子:
 
@@ -2817,7 +2817,7 @@ a = b
 /hi/g.exec(c).map(d)
 ```
 
-大家思考一个问题,上面代码段中第二句代码开头的斜杠(`/`)是除法运算符还是正则表达式的开头?答案是除法,因为如上代码等价于:
+大家思考一个问题,上面代码段中第二句代码开头的斜杠(`/`)是除法运算符还是正则表达式的开头?答案是除法,因为如上代码等价于:
 
 ```js
 a = b / hi / g.exec(c).map(d)
@@ -2835,14 +2835,59 @@ var a = {}
 /1/g
 ```
 
-如上两段代码所示,这两段代码具有相同的特点,即第一句代码的最后一个字符为 `{`,第二句代码的第一个字符为 `/`。大家思考一下哪一段代码中的斜杠是除法运算符,哪一段代码中的斜杠是正则表达式的开头?实际上第一段代码中的斜杠是正则,因为该斜杠之前的语境是函数定义,而第二段代码中的斜杠是除法,因为该斜杠之前的语境为表达式并且花括号(`{}`)的意义为对象字面量。
+如上两段代码所示,这两段代码具有相同的特点,即第一句代码的最后一个字符为 `{`,第二句代码的第一个字符为 `/`。大家思考一下哪一段代码中的斜杠是除法运算符,哪一段代码中的斜杠是正则表达式的开头?实际上第一段代码中的斜杠是正则,因为该斜杠之前的语境是函数定义,而第二段代码中的斜杠是除法,因为该斜杠之前的语境为表达式并且花括号(`{}`)的意义为对象字面量。
 
 实际上判断一个斜杠到底代表什么意义,应该综合考虑上下文语境,[ECMA 规范中](http://www.ecma-international.org/ecma-262/9.0/index.html#sec-ecmascript-language-lexical-grammar) 中清楚的已经告诉大家需要多种标志符号类型(`goal symbols`)来综合判断,并且还要考虑 `javascript` 这门语言的自动插入分号机制,以及其他可能产生歧义的地方。
 
-如果要实现一个完整的能够精确识别斜杠意义的解析器需要花费大量的精力并且编写大量的代码,但对于 `Vue` 来讲,去实现一个完整的解析器是一个收入与回报完全不对等的事情。后面我们在分析 `parseFilters` 函数时可以看到,`parseFilters` 函数对于正则的处理仅仅考虑了很小的一部分,但对于 `Vue` 来说,这已经足够了。还是那句话:**为什么一定要在绑定的表达式中写正则呢?用计算属性就可以了啊**。
+如果要实现一个完整的能够精确识别斜杠意义的解析器需要花费大量的精力并且编写大量的代码,但对于 `Vue` 来讲,去实现一个完整的解析器是一个收入与回报完全不对等的事情。后面我们在分析 `parseFilters` 函数时可以看到,`parseFilters` 函数对于正则的处理仅仅考虑了很小的一部分,但对于 `Vue` 来说,这已经足够了。还是那句话:**为什么一定要在绑定的表达式中写正则呢?用计算属性就可以了啊**。
 
 以上就是我们对 `parseFilters` 函数的作用和一些基本实现思路的讲解,接下来我们就具体到 `parseFilters` 函数中去,看看它真正的实现和最终的结果。
 
+打开 `src/compiler/parser/filter-parser.js` 文件找到 `parseFilters` 函数,如下是其函数签名:
+
+```js
+export function parseFilters (exp: string): string {}
+```
+
+`parseFilters` 函数接收绑定的属性值作为参数,在 `parseFilters` 函数的开头定义了一些变量,我们先来看如下这组变量:
+
+```js
+let inSingle = false
+let inDouble = false
+let inTemplateString = false
+let inRegex = false
+```
+
+这里定义了四个变量,分别是 `inSingle`、`inDouble`、`inTemplateString` 以及 `inRegex`,并且它们的初始值都为 `false`。这些变量的作用是什么呢?首先大家应该知道的是,大部分解析器在解析一段字符串的时候,都会把字符串当做一个字符流,从头到尾逐个字符读取。`parseFilters` 函数也不例外,`parseFilters` 函数会把接收到的字符串从头到尾逐个字符依次读取,当读取到字符 `'` 并且该字符串的前一个字符不是 `\` 时,则会将这个单引号字符作为字符串的开始,这时会把 `inSingle` 变量设置为 `true`,代表当前解析进入了由单引号包裹的字符串。所以对于后续读取的任何字符来讲,由于 `inSingle` 变量的值为真,所以这些字符都会被当做普通字符串的一部分来处理,直到解析器遇到了下一个能够代表字符串结束的单引号为止,此时会重新将 `inSingle` 变量的值设置为 `false`。
+
+所以我们可以理解为 `inSingle` 变量的作用是用来标识当前读取的字符是否在由单引号包裹的字符串中。同样的:
+
+* `inDouble` 变量是用来标识当前读取的字符是否在由 **双引号** 包裹的字符串中。
+* `inTemplateString` 变量是用来标识当前读取的字符是否在 **模板字符串** 中。
+* `inRegex` 变量是用来标识当前读取的字符是否在 **正则表达式** 中。
+
+接着我们再来看如下这三个变量:
+
+```js
+let curly = 0
+let square = 0
+let paren = 0
+```
+
+如上三个变量的初始值都为 `0`,其作用如下:
+
+* 在解析绑定的属性值时,每遇到一个左花括号(`{`),则 `curly` 变量的值就会加一,每遇到一个右花括号(`}`),则 `curly` 变量的值就会减一。
+* 在解析绑定的属性值时,每遇到一个左方括号(`[`),则 `square` 变量的值就会加一,每遇到一个右方括号(`]`),则 `square` 变量的值就会减一。
+* 在解析绑定的属性值时,每遇到一个左圆括号(`(`),则 `paren` 变量的值就会加一,每遇到一个右方括号(`)`),则 `paren` 变量的值就会减一。
+
+当 `parseFilters` 函数在解析属性值字符串并遇到一个管道符时,该管道符应不应该作为过滤器的分界线还要看以上三个变量是否为 `0`,如果以上三个变量至少有一个不为 `0`,则说明该管道符存在于花括号或方括号或圆括号之内,这时该管道符是不会被作为过滤器的分界线的,如下:
+
+```html
+<div :key="(aa | bb)"></div>
+```
+
+以上代码中绑定属性 `key` 的属性值中包含一个管道符,但是由于该管道符存在于圆括号内,所以它不会被作为过滤器的分界线。
+
 ### 增强的 class
 ### 增强的 style
 ### 特殊的 model