vue源码探索之过滤器解析过程

模板编译

<body>
    <div id="app">
        <span>{{ 1 | test(8) }}</span>
    </div>
</body>
<script src="./vue.js"></script>
<script>
    new Vue({
  el: "#app",
  filters: {
    test (val, b) {
        console.log(this)
        debugger
      return val + b
    }
  }
});

模板在编译成render函数时候会经过下面一系列流程:
vue源码探索之过滤器解析过程

parseText

主要在parseText函数解析文本

function parseText (
    text,
    delimiters
  ) {
    debugger
    var tagRE = delimiters ? buildRegex(delimiters) : defaultTagRE;
    if (!tagRE.test(text)) {
      return
    }
    var tokens = [];
    var rawTokens = [];
    var lastIndex = tagRE.lastIndex = 0;
    var match, index, tokenValue;
    while ((match = tagRE.exec(text))) {
      index = match.index;
      // push text token
      if (index > lastIndex) {
        rawTokens.push(tokenValue = text.slice(lastIndex, index));
        tokens.push(JSON.stringify(tokenValue));
      }
      // tag token
      var exp = parseFilters(match[1].trim());
      tokens.push(("_s(" + exp + ")"));
      rawTokens.push({ ‘@binding‘: exp });
      lastIndex = index + match[0].length;
    }
    if (lastIndex < text.length) {
      rawTokens.push(tokenValue = text.slice(lastIndex));
      tokens.push(JSON.stringify(tokenValue));
    }
    return {
      expression: tokens.join(‘+‘), 
      tokens: rawTokens // 解析成 ["_s(_f("test")(1,8))"]
    }
  }

_f函数就是resolveFilter函数

function resolveFilter (id) {
    debugger
    return resolveAsset(this.$options, ‘filters‘, id, true) || identity
  }
function resolveAsset (
    options,
    type,
    id,
    warnMissing
  ) {
    /* istanbul ignore if */
    if (typeof id !== ‘string‘) {
      return
    }
    var assets = options[type];
    // check local registration variations first
    if (hasOwn(assets, id)) { return assets[id] }
    var camelizedId = camelize(id);
    if (hasOwn(assets, camelizedId)) { return assets[camelizedId] }
    var PascalCaseId = capitalize(camelizedId);
    if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] }
    // fallback to prototype chain
    var res = assets[id] || assets[camelizedId] || assets[PascalCaseId];
    if (warnMissing && !res) {
      warn(
        ‘Failed to resolve ‘ + type.slice(0, -1) + ‘: ‘ + id,
        options
      );
    }
    return res
  }

resolveAsset就是取出我们在组件中定义在filters里面的test函数,由此可见当我们在定义filter函数中this是不指向当前组件实例的,指向window。如果要想拿到组件实例,可通过调用过滤器的时候,传入this

最终生成的render函数

vue源码探索之过滤器解析过程
vue源码探索之过滤器解析过程