vue源碼閱讀之parser

parser目錄下包含如下幾個文件,核心文件在于path.js。

  • directive.js:

    parseDirective
    
  • expression.js:

      parseExpression
    
  • path.js:

     getPath, 
     setPath, 
     parsePath
    
  • template.js:

    parseTemplate,
    cloneNode, 
    parseTemplate
    
  • text.js:
    parseText,
    tokensToExp,
    compileRegex

parser工作流程圖

函數(shù)解讀:

  • parseDirective: 判斷表達式中是否存在過濾器,如果存在提取出來
  • parseExpression: 負責將表達式添加getter 和 setter方法
  • makeGetterFn:將簡單字符串表達式添加scope作用域并轉(zhuǎn)化為function返回
  • compileGetter:將復雜字符串表達式進行正則替換并在變量后添加scope作用域
    例: status == "todo" 返回 scope.status == "todo"
  • compileSetter:將parse函數(shù)生成數(shù)組遍歷并將最后一個屬性作為最后的key

[path.js] 通過parse函數(shù)對 a.b.c 進行逐個字節(jié)掃描,最終獲得['a','b','c',raw:'a.b.c']數(shù)組

// actions
var APPEND = 0  // 拼接字符在keystr后
var PUSH = 1  // 將keystr添加到keys數(shù)組中
var INC_SUB_PATH_DEPTH = 2  // 拼接當前字符在keystr后,并且深度+1
var PUSH_SUB_PATH = 3   // 如果深度大于0將狀態(tài)置回IN_SUB_PATH,相反將keystr添加到keys數(shù)組

// states
var BEFORE_PATH = 0  // 初始狀態(tài)
var IN_PATH = 1   //  遇到空格 和 ]
var BEFORE_IDENT = 2  // 遇到' . ' 或 空格時
var IN_IDENT = 3  //  遇到字符串數(shù)字時
var IN_SUB_PATH = 4  //  遇到 ' 或 " 或 [ 時
var IN_SINGLE_QUOTE = 5  //  遇到 '
var IN_DOUBLE_QUOTE = 6  //  遇到 "
var AFTER_PATH = 7  //  結(jié)束狀態(tài)
var ERROR = 8  //  報錯

var pathStateMachine = []   // 狀態(tài) + 動作  管理倉庫

pathStateMachine[BEFORE_PATH] = {
  'ws': [BEFORE_PATH],
  'ident': [IN_IDENT, APPEND],
  '[': [IN_SUB_PATH],
  'eof': [AFTER_PATH]
}

pathStateMachine[IN_PATH] = {
  'ws': [IN_PATH],
  '.': [BEFORE_IDENT],
  '[': [IN_SUB_PATH],
  'eof': [AFTER_PATH]
}

pathStateMachine[BEFORE_IDENT] = {
  'ws': [BEFORE_IDENT],
  'ident': [IN_IDENT, APPEND]
}

pathStateMachine[IN_IDENT] = {
  'ident': [IN_IDENT, APPEND],
  '0': [IN_IDENT, APPEND],
  'number': [IN_IDENT, APPEND],
  'ws': [IN_PATH, PUSH],
  '.': [BEFORE_IDENT, PUSH],
  '[': [IN_SUB_PATH, PUSH],
  'eof': [AFTER_PATH, PUSH]
}

pathStateMachine[IN_SUB_PATH] = {
  "'": [IN_SINGLE_QUOTE, APPEND],
  '"': [IN_DOUBLE_QUOTE, APPEND],
  '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH],
  ']': [IN_PATH, PUSH_SUB_PATH],
  'eof': ERROR,
  'else': [IN_SUB_PATH, APPEND]
}

pathStateMachine[IN_SINGLE_QUOTE] = {
  "'": [IN_SUB_PATH, APPEND],
  'eof': ERROR,
  'else': [IN_SINGLE_QUOTE, APPEND]
}

pathStateMachine[IN_DOUBLE_QUOTE] = {
  '"': [IN_SUB_PATH, APPEND],
  'eof': ERROR,
  'else': [IN_DOUBLE_QUOTE, APPEND]
}

/* 
   開始狀態(tài)下當遇到對應字符會將狀態(tài)變化成對應狀態(tài)并執(zhí)行對應動作 
   我們以 a["b"].c 為線索進入parse函數(shù)并進行逐個字節(jié)掃描
   index=0時: 
   char='a'  mode=BEFORE_PATH  pathStateMachine[BEFORE_PATH]['ident']=[IN_IDENT, APPEND]   newchar="a",keys=[]
   index=1時 :
   char='['  mode=IN_IDENT pathStateMachine[IN_IDENT]['[']=[IN_SUB_PATH, PUSH]  newchar=undefined,keys=['a']
   index=2時 :
   char='"'  mode=IN_SUB_PATH pathStateMachine[IN_SUB_PATH]['"']=[IN_DOUBLE_QUOTE,APPEND]  newchar='"',keys=['a']
   index=3時 :
   char='b' mode=IN_DOUBLE_QUOTE pathStateMachine[IN_DOUBLE_QUOTE]['ident']= pathStateMachine[IN_DOUBLE_QUOTE]['else'] = [IN_DOUBLE_QUOTE,APPEND]  newchar='"b',keys=['a']
   index=4時 :
   char='"'  mode=IN_DOUBLE_QUOTE pathStateMachine[IN_DOUBLE_QUOTE]['"']=[IN_SUB_PATH,APPEND]  newchar='"b"',keys=['a']
   index=5時 :
   char="]" mode=IN_SUB_PATH pathStateMachine[IN_SUB_PATH][']']=[IN_PATH,PUSH_SUB_PATH]  newchar=undefined,keys=['a','b']
   index=6時 :
   char="."  mode=IN_PATH pathStateMachine[IN_PATH]['.']=[BEFORE_IDENT]  newchar=undefined,keys=['a','b']
   index=7時 :
   char="c"  mode=BEFORE_IDENT pathStateMachine[BEFORE_IDENT]['indent']=[IN_IDENT,APPEND] newchar='c',keys=['a','b']
   index=8時 :
   char=undefined mode=IN_IDENT pathStateMachine[IN_IDENT]['eof']=[AFTER_PATH,PUSH] newchar=undefined,keys=['a','b','c']

    最終循環(huán)完成當狀態(tài)變?yōu)锳FTER_PATH時,keys = ['a','b','c',raw:'a["b"].c']
*/

function parse (path) {
    var keys = []    
    var index = -1
    var mode = BEFORE_PATH
    var subPathDepth = 0
    var c, newChar, key, type, transition, action, typeMap
    var actions = []
    actions[PUSH] = function () {
        if (key !== undefined) {
            keys.push(key)
            key = undefined
        }
    }
    actions[APPEND] = function () {
        if (key === undefined) {
            key = newChar
        } else {
            key += newChar
        }
    }
    actions[INC_SUB_PATH_DEPTH] = function () {
         actions[APPEND]()
         subPathDepth++
    }
    actions[PUSH_SUB_PATH] = function () {
        if (subPathDepth > 0) {
            subPathDepth--
            mode = IN_SUB_PATH
            actions[APPEND]()
        } else {
            subPathDepth = 0
            key = formatSubPath(key)
            if (key === false) {
                return false
            } else {
                actions[PUSH]()
            }
        }
    }
    function maybeUnescapeQuote () {
          var nextChar = path[index + 1]
          if ((mode === IN_SINGLE_QUOTE && nextChar === "'") ||
          (mode === IN_DOUBLE_QUOTE && nextChar === '"')) {
              index++
              newChar = '\\' + nextChar
              actions[APPEND]()
              return true
          }
     }
     while (mode != null) {
          index++
          c = path[index]
          if (c === '\\' && maybeUnescapeQuote()) {
              continue
          }
          type = getPathCharType(c)
          typeMap = pathStateMachine[mode]
          transition = typeMap[type] || typeMap['else'] || ERROR
          if (transition === ERROR) {
              return // parse error
          }
          mode = transition[0]
          action = actions[transition[1]]
          if (action) {
              newChar = transition[2]
              newChar = newChar === undefined
              ? c
              : newChar
              if (action() === false) {
                    return
              }
          }
          if (mode === AFTER_PATH) {
               keys.raw = path
               return keys
          }
      }
}
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,923評論 18 139
  • ¥開啟¥ 【iAPP實現(xiàn)進入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,523評論 0 17
  • 1.創(chuàng)建文件夾 !/bin/sh mkdir -m 777 "%%1" 2.創(chuàng)建文件 !/bin/sh touch...
    BigJeffWang閱讀 10,186評論 3 53
  • 思路 決定內(nèi)容區(qū)域的大小和圖片種類數(shù)量圖片應該放多少行,多少列。必須是偶數(shù)整個區(qū)域應該是在圖片外多圍上一圈,也就是...
    Magician_Shiro閱讀 5,702評論 3 18
  • 這個夏天下了很大很多的雨,這個夏天也發(fā)生了很多不順的事
    詩經(jīng)丫丫閱讀 160評論 0 0